nodejs-实战


代码链接

问题

webpack5 打包的成果 node.vm.runInContext返回为undefined

背景

​ 为了实现类似于将配置上传到云端,然后需要用到的地方在云端读取在做一些操作,但是由于配置文件存在require的相互引用,所以需要使用webpack打包,然后再使用的配置的地方将打包结果还原

开始打包:

const mfs = new (require('memory-fs'))
const compileTask = webpack({
    mode: 'development',
    devtool: false,
    target: 'node',
    node: { global: true },
    entry: '打包入口',
    module:{
      rules: [
        {
          test: /\.proto$/,
          use: 'text-loader' 
        }
      ]
    },
    output: {
      path: '/whatever',
      filename: 'data.js',
      library: {
        type: 'umd'
      },
    }
  })

  compileTask.outputFileSystem = mfs // 由于不需要存储到磁盘上,mfs可以建立一个内存文件系统
  compileTask.run(function(err) {
    if (err) { return }
    const content = mfs.readFileSync('/whatever/data.js')
    // 模拟上传配置文件到云端
    fs.writeFileSync(__dirname + '/../business/' + businessName + '/data.js', content);
})

从云端读取并使用

  const data = fs.readFileSync(__dirname + '/business/list/data.js', "utf-8") // 模拟从云端读取
    vm.runInContext(data, vm.createContext({})) // global is no defined || 这里的返回结果为undefined
// 如果提示global is no defined 可以在webpack配加上
{
 ...
 output: {
    globalObject: 'this'
 }
 ...
}

浅看下打包产物,可以简化成 function( root, factory)(global, () => something),一个自执行函数,root就是global,factory就是打包结果,然后最终的执行结果就就是function(root, factory){}里面执行的逻辑,测试了下最后的结果会存在第二个else里面。

(function webpackUniversalModuleDefinition(root, factory) {
    if(typeof exports === 'object' && typeof module === 'object')
        module.exports = factory();
    else if(typeof define === 'function' && define.amd)
        define([], factory);
    else {
        var a = factory();
        for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
    }
})(global, () => {
return  (() => { 
    var __webpack_modules__ = ({

"./src/list/protocol.proto":

((module) => {

module.exports = "// message ExtendInfo {\n//   required string info = 1;\n// }\nmessage List {\n  required int32 id = 1;\n  required string title = 2;\n  required int32 price = 3;\n  // optional ExtendInfo extendInfo = 4;\n}\n\nmessage Response {\n  repeated  List list = 1;\n}\n\nmessage Request {\n  required string sort = 1;\n  optional string order = 2;\n}"

 }),

 "./src/list/data.js":
 ((module, __unused_webpack_exports, __webpack_require__) => {

module.exports = {
  List : {
    protocol: 'list-rpc',
    ip: '127.0.0.1',
    port: 4003,
    protocolFile:  __webpack_require__(/*! ./src/list/protocol.proto */ "./src/list/protocol.proto"),
    responseStruct: 'Response',
    requestStruct: 'Request',
    then: res => res 
  },
  ExtendInfo: {
    protocol: 'http',
    url: 'http://127.0.0.1:4002',
    then: res => res
  }
}


/***/ })

/******/     });
/************************************************************************/
/******/     // The module cache
/******/     var __webpack_module_cache__ = {};
/******/     
/******/     // The require function
/******/     function __webpack_require__(moduleId) {
/******/         // Check if module is in cache
/******/         var cachedModule = __webpack_module_cache__[moduleId];
/******/         if (cachedModule !== undefined) {
/******/             return cachedModule.exports;
/******/         }
/******/         // Create a new module (and put it into the cache)
/******/         var module = __webpack_module_cache__[moduleId] = {
/******/             // no module.id needed
/******/             // no module.loaded needed
/******/             exports: {}
/******/         };
/******/     
/******/         // Execute the module function
/******/         __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/     
/******/         // Return the exports of the module
/******/         return module.exports;
/******/     }
/******/     
/************************************************************************/
/******/     
/******/     // startup
/******/     // Load entry module and return exports
/******/     // This entry module is referenced by other modules so it can't be inlined
/******/     var __webpack_exports__ = __webpack_require__("./src/list/data.js");
/******/     
/******/     return __webpack_exports__;
/******/ })()
;
});

最开始我一直纠结于vm.runInContext(data, vm.createContext({}))返回一直为undefined,后面转换思路,我可以定义一个global,最后global就会引用打包结果,异曲同工,这样解决了获取不到webpack产物的问提。

 let dataConfig = {}
 vm.runInContext(app[routepath].data, vm.createContext({ global: dataConfig }))

我使用的版本

 "webpack": "^5.73.0"
 "webpack-cli": "^4.10.0"

文章作者: 木叶勇
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 木叶勇 !
  目录