问题
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"