+
80
-

请问nodejs中如何动态加载执行js文件?

现在有个main.js,还要许多子文件js在文件夹js中,请问nodejs中如何动态加载执行js文件?

网友回复

+
0
-

有两种方式

第一种、加载js文件compile

//main.js
const fs = require('fs')
fs.readFile = util.promisify(fs.readFile)
const bundle = await fs.readFile('./bundle.js', 'utf-8') //此时的bundle为String
const m = new module.constructor()
m._compile(bundle, 'bundle.js') // 第一个参数为要执行的代码字符串,第二个参数为文件名
//此时就可以通过m.exports来调用bundle.js文件中exports出来的东西

这种如果子文件有require的话就会出现找不到包

第二种、vm环境执行

//main.js
const fs = require('fs')
const NativeModule = require('module')
const vm = require('vm')

fs.readFile = util.promisify(fs.readFile)
const bundle = await fs.readFile('./bundle.js', 'utf-8') //此时的bundle为String

const getModuleFromString = (bundle, filename) => {
	const m = { exports: {} }
	const wrapper = NativeModule.wrap(bundle)
	const script = new vm.Script(wrapper, { 
		filename,
		displayErrors: true
	})
	const result = script.runInThisContext() // 此处可以指定代码的执行环境,此api在nodejs文档中有介绍
	result.call(m.exports, m.exports, require, m) // 执行wrapper函数,此处传入require就解决了第一种方法不能require的问题
	return m
}

const m = getModuleFromString(bundle, 'bundle.js')

这样就方便我们传入exports、require、module等参数,这些参数就是bundle代码执行过程中的module.exports,require,module,这样就方便了我们去定制这些参数,注意此时得到的wrapper依然是字符串的形式。然后通过vm模块的vm.Script方法去执行这段代码

其中,runInThisContext 相当于一个全新的环境中执行代码,不会影响当前作用域的对象。而runInNewContext与runInContext则能指定是上下文对象,区别是一个普通对象或一个context对象。换言之,runInNewContext与runInContext能局部影响当前作用域的对象。要与当前环境完全进行交互的话,就需要用到危险的eval。在node.js自带的加载体系中,显然没有这样的勇气,使用的是runInThisContext。并且在这之前做了许多工作,如把用户的JS文件里面的内容再包一层( NativeModule.wrap),还有其他凌散操作,加之是同步操作,实际上是一种效率很糟的加载方式。唯一的好处是,使用了同步,让代码编写起来简单多了。

我知道答案,我要回答