node.js 문서에서 :
모듈은 처음로드 된 후 캐시됩니다. 이것은 require ( 'foo')에 대한 모든 호출이 동일한 파일로 해석되면 정확히 동일한 객체를 반환한다는 것을 의미합니다.
이 캐시를 무효화하는 방법이 있습니까? 즉, 단위 테스트의 경우 각 테스트가 새로운 객체에서 작동하기를 원합니다.
node.js 문서에서 :
모듈은 처음로드 된 후 캐시됩니다. 이것은 require ( 'foo')에 대한 모든 호출이 동일한 파일로 해석되면 정확히 동일한 객체를 반환한다는 것을 의미합니다.
이 캐시를 무효화하는 방법이 있습니까? 즉, 단위 테스트의 경우 각 테스트가 새로운 객체에서 작동하기를 원합니다.
답변:
순환 종속성이있는 경우에도 문제없이 require.cache의 항목을 항상 안전하게 삭제할 수 있습니다. 삭제하면 모듈 오브젝트 자체가 아닌 캐시 된 모듈 오브젝트에 대한 참조 만 삭제하므로 순환 종속성의 경우이 모듈 오브젝트를 참조하는 오브젝트가 여전히 있으므로 모듈 오브젝트가 GC되지 않습니다.
당신이 가지고 있다고 가정 해보십시오 :
스크립트 a.js :
var b=require('./b.js').b;
exports.a='a from a.js';
exports.b=b;
및 스크립트 b.js :
var a=require('./a.js').a;
exports.b='b from b.js';
exports.a=a;
당신이 할 때 :
var a=require('./a.js')
var b=require('./b.js')
당신은 얻을 것이다 :
> a
{ a: 'a from a.js', b: 'b from b.js' }
> b
{ b: 'b from b.js', a: undefined }
이제 b.js를 편집하면 :
var a=require('./a.js').a;
exports.b='b from b.js. changed value';
exports.a=a;
하고 :
delete require.cache[require.resolve('./b.js')]
b=require('./b.js')
당신은 얻을 것이다 :
> a
{ a: 'a from a.js', b: 'b from b.js' }
> b
{ b: 'b from b.js. changed value',
a: 'a from a.js' }
===
위의 내용은 node.js를 직접 실행하는 경우에 유효합니다. 그러나 jest 와 같은 자체 모듈 캐싱 시스템이있는 도구를 사용하는 경우 올바른 명령문은 다음과 같습니다.
jest.resetModules();
{ ... a: undefined}필요할 때 이유를 설명해 주 b.js시겠습니까? 나는 같을 것으로 예상된다 'a from a.js'. 감사합니다
b[a]순환 의존성이 있기 때문에 내가 수집 한 것은 처음으로 정의되지 않았습니다. a.js요구 b.js하는 것이 필요합니다 a.js. a.js아직 완전히로드되지 않았으며 아직 exports.a정의되지 않았으므로 b.js아무 것도 얻지 마십시오 .
require.main.require(path)여기에 설명 된대로 사용하면이 작업을 수행 할 수있는 방법이 있습니까? stackoverflow.com/questions/10860244/…
항상 모듈을 다시로드하려면 다음 기능을 추가하십시오.
function requireUncached(module) {
delete require.cache[require.resolve(module)];
return require(module);
}
그런 다음 requireUncached('./myModule')require 대신 사용하십시오 .
fs.watch파일 변경을 수신 하는 방법 과 함께 사용하면 완벽 합니다.
예, 액세스 하려는 모듈의 이름이있는 require.cache[moduleName]곳을 통해 캐시에 액세스 할 수 moduleName있습니다. 호출하여 항목을 삭제하면 delete require.cache[moduleName]발생합니다 require실제 파일을로드 할 수 있습니다.
모듈과 관련된 모든 캐시 파일을 제거하는 방법은 다음과 같습니다.
/**
* Removes a module from the cache
*/
function purgeCache(moduleName) {
// Traverse the cache looking for the files
// loaded by the specified module name
searchCache(moduleName, function (mod) {
delete require.cache[mod.id];
});
// Remove cached paths to the module.
// Thanks to @bentael for pointing this out.
Object.keys(module.constructor._pathCache).forEach(function(cacheKey) {
if (cacheKey.indexOf(moduleName)>0) {
delete module.constructor._pathCache[cacheKey];
}
});
};
/**
* Traverses the cache to search for all the cached
* files of the specified module name
*/
function searchCache(moduleName, callback) {
// Resolve the module identified by the specified name
var mod = require.resolve(moduleName);
// Check if the module has been resolved and found within
// the cache
if (mod && ((mod = require.cache[mod]) !== undefined)) {
// Recursively go over the results
(function traverse(mod) {
// Go over each of the module's children and
// traverse them
mod.children.forEach(function (child) {
traverse(child);
});
// Call the specified callback providing the
// found cached module
callback(mod);
}(mod));
}
};
사용법은 다음과 같습니다.
// Load the package
var mypackage = require('./mypackage');
// Purge the package from cache
purgeCache('./mypackage');
이 코드는 동일한 리졸버를 사용하므로 require필요한 것을 지정하십시오.
"유닉스는 사용자가 어리석은 일을하는 것을 막기 위해 고안된 것이 아니었다. – 더그 기윈
캐시되지 않은 모듈로드를 명시 적으로 수행 할 수있는 방법 이 있어야 한다고 생각합니다 .
require.uncache함수에 추가 할 것 입니다. ```// github.com/joyent/node/issues/8266 참조 Object.keys (module.constructor._pathCache) .forEach (function (k) {if (k.indexOf (moduleName)> 0) delete module.constructor ._pathCache [k];}); ```당신이 모듈을 필요로했다가 제거했다가 같은 모듈을 다시 설치했지만 package.json에 다른 주 스크립트를 가진 다른 버전을 사용했다고 가정하면 다음 주 스크립트는 존재하지 않기 때문에 실패합니다. 그것은 캐시에Module._pathCache
require.uncache
우리는 코드 를 테스트 하는 동안이 정확한 문제가 있었으며 ( 캐시 된 모듈을 삭제하여 새로운 상태로 다시 요청할 수 있음 ) 다양한 StackOverflow 질문 및 답변에 대한 사람들의 모든 제안 을 검토 하고 간단한 node.js 모듈을 구성했습니다 ( 테스트와 함께 ) :
예상 한대로 게시 된 npm 패키지와 로컬로 정의 된 모듈 모두 에서 작동 합니다. Windows, Mac, Linux 등
사용법은 매우 간단합니다.
npm에서 모듈을 설치하십시오.
npm install decache --save-dev
// require the decache module:
const decache = require('decache');
// require a module that you wrote"
let mymod = require('./mymodule.js');
// use your module the way you need to:
console.log(mymod.count()); // 0 (the initial state for our counter is zero)
console.log(mymod.incrementRunCount()); // 1
// delete the cached module:
decache('./mymodule.js');
//
mymod = require('./mymodule.js'); // fresh start
console.log(mymod.count()); // 0 (back to initial state ... zero)
질문이 있거나 더 많은 예제가 필요하면 GitHub 문제를 생성하십시오 : https://github.com/dwyl/decache/issues
Jest를 사용하는 사람이라면 Jest가 자체 모듈 캐싱을 수행하기 때문에 내장 기능이 jest.resetModules있습니다. 각 테스트 후 :
afterEach( function() {
jest.resetModules();
});
제안 된 다른 답변처럼 decache 를 사용하려고 시도한 후에 이것을 발견 했습니다. Anthony Garvan 에게 감사합니다 .
기능 문서는 여기에 있습니다 .
해결책은 다음을 사용하는 것입니다.
delete require.cache[require.resolve(<path of your script>)]
저와 같이 이것에 약간 새로운 사람들을위한 몇 가지 기본적인 설명을 여기에서 찾으십시오.
example.js디렉토리의 루트에 더미 파일 이 있다고 가정 하십시오.
exports.message = "hi";
exports.say = function () {
console.log(message);
}
그렇다면 당신 require()은 이것을 좋아합니다 :
$ node
> require('./example.js')
{ message: 'hi', say: [Function] }
그런 다음 다음과 같은 줄을 추가하십시오 example.js.
exports.message = "hi";
exports.say = function () {
console.log(message);
}
exports.farewell = "bye!"; // this line is added later on
콘솔에서 계속하면 모듈이 업데이트되지 않습니다.
> require('./example.js')
{ message: 'hi', say: [Function] }
그때 당신은 러프의 대답에delete require.cache[require.resolve()] 표시된 것을 사용할 수 있습니다 :
> delete require.cache[require.resolve('./example.js')]
true
> require('./example.js')
{ message: 'hi', say: [Function], farewell: 'bye!' }
따라서 캐시가 정리되고 require()파일의 내용을 다시 캡처하여 모든 현재 값을로드합니다.
rewire 는이 사용 사례에 적합하며 각 호출마다 새 인스턴스를 얻습니다. node.js 단위 테스트를위한 쉬운 의존성 주입.
rewire는 모듈에 특수 setter 및 getter를 추가하여 더 나은 단위 테스트를 위해 해당 동작을 수정할 수 있습니다. 당신은 할 수있다
프로세스 누출 개인 변수와 같은 다른 모듈 또는 전역에 대한 모의는 모듈 내의 변수보다 우선합니다. rewire는 파일을로드하지 않고 내용을 평가하여 노드의 요구 메커니즘을 에뮬레이트합니다. 실제로 그것은 모듈을로드하기 위해 노드 자신의 요구를 사용합니다. 따라서 모듈은 테스트 환경에서 일반 환경 (수정 사항 제외)과 동일하게 작동합니다.
모든 카페인 중독자에게 희소식 : 재 와이어는 Coffee-Script에서도 작동합니다. 이 경우 CoffeeScript가 devDependencies에 나열되어 있어야합니다.
luff 's answer에 한 줄을 더 추가하고 매개 변수 이름을 변경합니다.
function requireCached(_module){
var l = module.children.length;
for (var i = 0; i < l; i++)
{
if (module.children[i].id === require.resolve(_module))
{
module.children.splice(i, 1);
break;
}
}
delete require.cache[require.resolve(_module)];
return require(_module)
}
예, 캐시를 무효화 할 수 있습니다.
캐시는 require.cache라는 객체에 저장되며 파일 이름에 따라 직접 액세스 할 수 있습니다 (예 : 명령문 에서 사용하는 /projects/app/home/index.js것과 반대 ). ./homerequire('./home')
delete require.cache['/projects/app/home/index.js'];
우리 팀은 다음 모듈이 유용하다는 것을 알았습니다. 특정 모듈 그룹을 무효화합니다.
답변의 주석에 코드를 깔끔하게 추가 할 수 없었습니다. 그러나 @Ben Barkay의 대답을 사용하고 이것을 require.uncache함수에 추가 합니다.
// see https://github.com/joyent/node/issues/8266
// use in it in @Ben Barkay's require.uncache function or along with it. whatever
Object.keys(module.constructor._pathCache).forEach(function(cacheKey) {
if ( cacheKey.indexOf(moduleName) > -1 ) {
delete module.constructor._pathCache[ cacheKey ];
}
});
모듈이 필요했다가 제거한 다음 동일한 모듈을 다시 설치했지만 패키지에 다른 기본 스크립트가있는 다른 버전을 사용했다고 가정 해보십시오. Module._pathCache
나는 '무효화'가 의미하는 바를 100 % 확신하지 못하지만 require캐시 위에 지우려면 명령문 위에 다음을 추가 할 수 있습니다 .
Object.keys(require.cache).forEach(function(key) { delete require.cache[key] })
@ Dancrumb의 의견 에서 가져 왔습니다.
requireUncached 상대 경로로 : 🔥
const requireUncached = require => module => {
delete require.cache[require.resolve(module)];
return require(module);
};
module.exports = requireUncached;
상대 경로로 requireUncached를 호출하십시오.
const requireUncached = require('../helpers/require_uncached')(require);
const myModule = requireUncached('./myModule');
두 단계 절차를 따르면 완벽하게 작동합니다.
Model파일을 'mymodule.js'동적으로 변경 한 후 몽구스 모델 에서 사전 컴파일 된 모델을 먼저 삭제 한 다음 require-reload를 사용하여 다시로드해야합니다.
Example:
// Delete mongoose model
delete mongoose.connection.models[thisObject.singular('mymodule')]
// Reload model
var reload = require('require-reload')(require);
var entityModel = reload('./mymodule.js');
단위 테스트를 위해 사용하는 또 다른 좋은 도구는 proxyquire 입니다. 모듈을 프록시 요구할 때마다 모듈 캐시가 무효화되고 새 모듈이 캐시됩니다. 또한 테스트중인 파일에 필요한 모듈을 수정할 수 있습니다.
로드 후 캐시에서 모듈을 삭제하는 작은 모듈을 만들었습니다. 다음에 필요할 때 모듈을 다시 평가해야합니다. 참조 https://github.com/bahmutov/require-and-forget를
// random.js
module.exports = Math.random()
const forget = require('require-and-forget')
const r1 = forget('./random')
const r2 = forget('./random')
// r1 and r2 will be different
// "random.js" will not be stored in the require.cache
추신 : "자체 파괴"를 모듈 자체에 넣을 수도 있습니다. 참조 https://github.com/bahmutov/unload-me를
PSS : 내 https://glebbahmutov.com/blog/hacking-node-require/ 에서 Node에 대한 추가 트릭