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が使用するので、必要なものを何でも指定してください。
「Unixは、ユーザーが愚かなことをするのを止めるようには設計されていません。–ダググウィン
キャッシュされていないモジュールを明示的にロードする方法があったはずだと思います。
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に異なるメインスクリプトが含まれる別のバージョンを使用したとします。次のrequireは、そのメインスクリプトが存在しないため失敗しますキャッシュされていますModule._pathCache
require.uncache
コードのテスト中にこの正確な問題がありました(キャッシュされたモジュールを削除して、新しい状態で再要求できるようにするため)。さまざまなStackOverflowのQ&Aに関する人々の提案をすべて見直し、単純な 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
解決策は以下を使用することです:
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は特別なセッターとゲッターをモジュールに追加するので、ユニットテストを改善するためにそれらの動作を変更できます。してもいいです
他のモジュールまたはプロセスリークのようなグローバルのモックを注入するプライベート変数は、モジュール内の変数をオーバーライドします。rewireはファイルをロードせず、ノードの必要なメカニズムをエミュレートするためにコンテンツを評価しません。実際、それはモジュールをロードするためにノード自身の要求を使用します。したがって、モジュールはテスト環境でも通常の状況とまったく同じように動作します(変更を除く)。
すべてのカフェイン中毒者にとって朗報です。rewireはCoffee-Scriptでも機能します。この場合、CoffeeScriptをdevDependenciesにリストする必要があることに注意してください。
luffの答えに1行追加して、パラメーター名を変更します。
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とは対照的に、./homeあなたが使用しているrequire('./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 ];
}
});
モジュールが必要で、それをアンインストールしてから、同じモジュールを再インストールしたが、package.jsonに異なるメインスクリプトが含まれている別のバージョンを使用したとします。 Module._pathCache
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');
次の2つのステップの手順は、私にとって完全に機能しています。
Modelファイルを'mymodule.js'動的に変更した後、mongooseモデルのプリコンパイル済みモデルを削除してから、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
PS:モジュール自体に「自己破壊」を挿入することもできます。https://github.com/bahmutov/unload-meを参照してください
PSS:https ://glebbahmutov.com/blog/hacking-node-require/でNodeを使用するより多くのトリックが必要です