node.js require () 캐시-무효화 할 수 있습니까?
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' }
항상 모듈을 다시로드하려면 다음 기능을 추가하십시오.
function requireUncached(module){
delete require.cache[require.resolve(module)]
return require(module)
}
그런 다음 requireUncached('./myModule')
require 대신 사용하십시오 .
예, 액세스 하려는 모듈의 이름이있는 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
원하는 것을 지정하십시오.
"유닉스는 사용자가 어리석은 일을하는 것을 막기 위해 고안된 것이 아니며, 그렇게하면 영리한 일을하는 것도 막을 수 있습니다." – 더그 기윈
캐시되지 않은 모듈로드를 명시 적으로 수행 할 수있는 방법 이 있어야 한다고 생각합니다 .
그 간단한 모듈이 있습니다 ( 테스트 포함 )
우리는 코드 를 테스트 하는 동안이 정확한 문제가 있었으며 ( 캐시 모듈을 삭제하여 새로운 상태로 다시 요구할 수 있음 ) 다양한 StackOverflow 질문 및 답변에 대한 사람들의 모든 제안 을 검토 하고 간단한 node.js 모듈을 구성했습니다 ( 테스트와 함께 ) :
예상 한대로 게시 된 npm 패키지와 로컬로 정의 된 모듈 모두 에서 작동 합니다. Windows, Mac, Linux 등
어떻게? ( 사용법 )
사용법은 매우 간단합니다.
설치
npm에서 모듈을 설치하십시오.
npm install decache --save-dev
코드에서 사용하십시오.
// require the decache module:
var decache = require('decache');
// require a module that you wrote"
var 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
해결책은 다음을 사용하는 것입니다.
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()
파일의 내용을 다시 캡처하여 모든 현재 값을로드합니다.
Jest를 사용하는 사람은 Jest가 자체 모듈 캐싱을 수행하기 때문에이를위한 내장 기능이 jest.resetModules
있습니다. 예를 들어 실행 해야 합니다. 각 테스트 후 :
afterEach( function() {
jest.resetModules();
});
제안 된 다른 답변처럼 decache 를 사용하려고 시도한 후에 이것을 발견 했습니다. Anthony Garvan 에게 감사합니다 .
기능 문서는 여기에 있습니다 .
rewire 는이 사용 사례에 적합하며 각 호출마다 새로운 인스턴스를 얻습니다. node.js 단위 테스트를위한 쉬운 의존성 주입.
rewire는 모듈에 특수 setter 및 getter를 추가하여 더 나은 단위 테스트를 위해 해당 동작을 수정할 수 있습니다. 당신은 할 수있다
프로세스 누출 개인 변수와 같은 다른 모듈 또는 전역에 대한 모의는 모듈 내의 변수보다 우선합니다. rewire는 파일을로드하지 않고 내용을 평가하여 노드의 요구 메커니즘을 에뮬레이트합니다. 실제로 그것은 모듈을로드하기 위해 노드 자신의 필요를 사용합니다. 따라서 모듈은 테스트 환경에서 일반 환경 (수정 사항 제외)과 동일하게 작동합니다.
모든 카페인 중독자에게 희소식 : 재 와이어는 Coffee-Script에서도 작동합니다. 이 경우 CoffeeScript가 devDependencies에 나열되어 있어야합니다.
예, 캐시를 무효화 할 수 있습니다.
캐시는 require.cache라는 객체에 저장되며 파일 이름에 따라 직접 액세스 할 수 있습니다 (예 : 명령문 에서 사용하는 /projects/app/home/index.js
것과 반대 )../home
require('./home')
delete require.cache['/projects/app/home/index.js'];
우리 팀은 다음 모듈이 유용하다는 것을 알았습니다. 특정 모듈 그룹을 무효화합니다.
https://www.npmjs.com/package/node-resource
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)
}
답변의 주석에 코드를 깔끔하게 추가 할 수 없었습니다. 그러나 @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
두 단계 절차를 따르면 완벽하게 작동합니다.
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에 대한 추가 트릭
참고 URL : https://stackoverflow.com/questions/9210542/node-js-require-cache-possible-to-invalidate
'development' 카테고리의 다른 글
Html.ActionLink가“? Length = 4”로 렌더링되는 이유 (0) | 2020.03.15 |
---|---|
IntelliJ IDEA에서 이전보기 위치로 이동 (뒤로 / 앞으로 이동)에 대한 키보드 단축키 (0) | 2020.03.15 |
데이터 프레임의 샘플 임의 행 (0) | 2020.03.15 |
레일스 루트 디렉토리 경로? (0) | 2020.03.15 |
Redis에 사용되는 기본 데이터 구조는 무엇입니까? (0) | 2020.03.15 |