本文章的内容在 nodejs v16 版本下测试通过。

如果要使用 ES 模块而不是 CommonJS 模块构建 Node.js 应用程序,可以通过使用.mjs或者在package.json中添加"type": "module",这样就可以使用ESM了。

问题

ESM中没有了__filename__direname这两个变量,并且不能直接导入JSON文件。

如果程序中用到了__filename__direname,则会遇到这样的错误ReferenceError: __dirname is not defined in ES module scopeReferenceError: __filename is not defined in ES module scope

如果使用import packageConfig from "../package.json"来导入package.json

你会遇到这样的错误 TypeError [ERR_IMPORT_ASSERTION_TYPE_MISSING]: Module "file:///.../package.json" needs an import assertion of type "json"

解决办法

通过Object.definePropertyglobal添加loadJSONgetFileNamegetDirName三个函数,扩展esm模式下的 global 属性。代码如下

// expandGlobal.js
import url from "node:url";
import path from "node:path";
import { createRequire } from "node:module";

Object.defineProperty(global, "loadJSON", {
  get() {
    return (filepath, importMetaUrl) => {
      const reg = /\S+.json$/g;
      if (reg.test(filepath)) {
        const require = createRequire(importMetaUrl);
        return require(filepath);
      } else {
        throw new Error("loadJSON 的参数必须是一个json文件");
      }
    };
  },
  enumerable: true,
  configurable: false,
  // writable: false,
});

Object.defineProperty(global, "getFileName", {
  get() {
    return (importMetaUrl) => {
      return url.fileURLToPath(importMetaUrl);
    };
  },
  enumerable: true,
  configurable: false,
  // writable: false,
});

Object.defineProperty(global, "getDirName", {
  get() {
    return (importMetaUrl) => {
      return path.dirname(url.fileURLToPath(importMetaUrl));
    };
  },
  enumerable: true,
  configurable: false,
  // writable: false,
});

使用

import "./expandGlobal.js";

console.log(global.getFileName(import.meta.url));
console.log(global.getDirName(import.meta.url));
console.log(global.loadJSON("../package.json",import.meta.url));

执行上述代码时,您将看到类似于以下内容的输出:

/Users/goodman/Desktop/Dev/node/node_kindacode/src/index.js
/Users/goodman/Desktop/Dev/node/node_kindacode/src

{                                                            
  name: 'nodejs',                                            
  version: '1.0.0',                                          
  type: 'module',                                            
  packageManager: 'pnpm@7.5.1',                              
  bin: { testcli: './src/cli/index.js' },                    
  dependencies: { 
      ......
   }       
}                 

结论

现在就可以像以前一样愉快的在 ESM构建的 Node.js 了。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐