[node.js] 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' }

===

위의 내용은 node.js를 직접 실행하는 경우에 유효합니다. 그러나 jest 와 같은 자체 모듈 캐싱 시스템이있는 도구를 사용하는 경우 올바른 명령문은 다음과 같습니다.

jest.resetModules();


답변

항상 모듈을 다시로드하려면 다음 기능을 추가하십시오.

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 모듈을 구성했습니다 ( 테스트와 함께 ) :

https://www.npmjs.com/package/ decache

예상 한대로 게시 된 npm 패키지와 로컬로 정의 된 모듈 모두 에서 작동 합니다. Windows, Mac, Linux 등

빌드 상태
codecov.io
코드 기후 유지 관리
종속성 상태
devDependencies 상태

어떻게? ( 사용법 )

사용법은 매우 간단합니다.

설치

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에 나열되어 있어야합니다.