本篇文章帶大家了解一下node中你不知道的__dirname和__filename變量,有一定的參考價值,希望對大家有所幫助!
1.問題背景
寫這篇文章的背景在于今天遇到一個神奇的報錯,一起來看下
// index.js console.log(__filename); // 執(zhí)行 node index.js // ReferenceError: __filename is not defined in ES module scope
在node環(huán)境訪問全局變量__filename居然報錯,什么原因呢??于是開始了一路的探索,最終找到問題的根源。
2. node模塊機(jī)制
我們知道早期node.js的模塊標(biāo)準(zhǔn)采用commonjs模塊規(guī)范,然而在nodejs版本v13.2.0中,開始支持ES Modules模塊規(guī)范,我們可以有以下幾種方式在node中使用ES Modules模塊
- 將文件后綴命名為.mjs
- package.json 新增 "type": "module"字段
當(dāng)我們在node中使用ES Modules貴方,以下全局對象和變量將不可用
- require
- module.exports
- exports
- __filename
- __dirname
- NODE_PATH
3. 為什么采用commonjs模塊化可以使用__filename和__dirname?
這個問題,主要?dú)w結(jié)于commonjs模塊下nodejs的運(yùn)行機(jī)制,很多人可能認(rèn)為__filename就是node環(huán)境中的全局變量,當(dāng)出現(xiàn)這個問題的時候,我們才意識到,這兩個不是Node中真正的全局變量。
看一段簡單的js代碼
(function(){ console.log(arguments) // [1,2,3] })(1,2,3)
arguments在函數(shù)內(nèi)部可以拿到調(diào)用函數(shù)時傳入的參數(shù)。
我們在node commonjs模塊中執(zhí)行以下代碼
// index.js console.log(arguments); [Arguments] { '0': {}, '1': [Function: require] { resolve: [Function: resolve] { paths: [Function: paths] }, main: Module { id: '.', path: 'E:\nodeProjectStorehouse\nodeStudyFromBook', exports: {}, filename: 'E:\nodeProjectStorehouse\nodeStudyFromBook\cc.cjs', loaded: false, children: [], paths: [Array] }, extensions: [Object: null prototype] { '.js': [Function (anonymous)], '.json': [Function (anonymous)], '.node': [Function (anonymous)] }, cache: [Object: null prototype] { 'E:\nodeProjectStorehouse\nodeStudyFromBook\cc.cjs': [Module] } }, '2': Module { id: '.', path: 'E:\nodeProjectStorehouse\nodeStudyFromBook', exports: {}, filename: 'E:\nodeProjectStorehouse\nodeStudyFromBook\cc.cjs', loaded: false, children: [], paths: [ 'E:\nodeProjectStorehouse\nodeStudyFromBook\node_modules', 'E:\nodeProjectStorehouse\node_modules', 'E:\node_modules' ] }, '3': 'E:\nodeProjectStorehouse\nodeStudyFromBook\cc.cjs', '4': 'E:\nodeProjectStorehouse\nodeStudyFromBook'
我們可以看到,arguments有5個參數(shù),這5個參數(shù)就是exports, require, module, __filename, __dirname
到這里我們就清楚的知道,__filename不是全局變量,而是外層傳入的參數(shù)而已
既然這樣,我們在ES Modules模塊下,訪問arguments看下結(jié)果是什么?
// index.js ES modules console.log(arguments); // ReferenceError: arguments is not defined
4. ES Modules下如何使用__filename和__dirname?
node官方文檔建議使用import.meta.url變相的提供
// import.meta.url 返回模塊的絕對的 `file:` URL。 // url模塊中fileURLToPath()函數(shù),返回完全解析的特定于平臺的 Node.js 文件路徑 // path模塊中dirname()函數(shù),返回路徑的目錄路徑 import { fileURLToPath } from 'url'; import { dirname } from 'path'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename);