- Node.js Design Patterns
- Mario Casciaro Luciano Mammino
- 606字
- 2021-06-18 18:15:06
ESM and CommonJS differences and interoperability
We already mentioned several important differences between ESM and CommonJS, such as having to explicitly specify file extensions in imports with ESM, while file extensions are totally optional with the CommonJS require function.
Let's close this chapter by discussing some other important differences between ESM and CommonJS and how the two module systems can work together when necessary.
ESM runs in strict mode
ES modules run implicitly in strict mode. This means that we don't have to explicitly add the "use strict" statements at the beginning of every file. Strict mode cannot be disabled; therefore, we cannot use undeclared variables or the with statement or have other features that are only available in non-strict mode, but this is definitely a good thing, as strict mode is a safer execution mode.
If you are curious to find out more about the differences between the two modes, you can check out a very detailed article on MDN Web Docs (https://nodejsdp.link/strict-mode).
Missing references in ESM
In ESM, some important CommonJS references are not defined. These include require, exports, module.exports, __filename, and __dirname. If we try to use any of them within an ES module, since it also runs in strict mode, we will get a ReferenceError:
console.log(exports) // ReferenceError: exports is not defined
console.log(module) // ReferenceError: module is not defined
console.log(__filename) // ReferenceError: __filename is not defined
console.log(__dirname) // ReferenceError: __dirname is not defined
We already discussed at length the meaning of exports and module in CommonJS; __filename and __dirname represent the absolute path to the current module file and the absolute path to its parent folder. Those special variables can be very useful when we need to build a path relative to the current file.
In ESM, it is possible to get a reference to the current file URL by using the special object import.meta. Specifically, import.meta.url is a reference to the current module file in a format similar to file:///path/to/current_module.js. This value can be used to reconstruct __filename and __dirname in the form of absolute paths:
import { fileURLToPath } from 'url'
import { dirname } from 'path'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
It is also possible to recreate the require() function as follows:
import { createRequire } from 'module'
const require = createRequire(import.meta.url)
Now we can use require() to import functionality coming from CommonJS modules in the context of ES modules.
Another interesting difference is the behavior of the this keyword.
In the global scope of an ES module, this is undefined, while in CommonJS, this is a reference to exports:
// this.js - ESM
console.log(this) // undefined
// this.cjs – CommonJS
console.log(this === exports) // true
Interoperability
We discussed in the previous section how to import CommonJS modules in ESM by using the module.createRequire function. It is also possible to import CommonJS modules from ESM by using the standard import syntax. This is only limited to default exports, though:
import packageMain from 'commonjs-package' // Works
import { method } from 'commonjs-package' // Errors
Unfortunately, it is not possible to import ES modules from CommonJS modules.
Also, ESM cannot import JSON files directly as modules, a feature that is used quite frequently with CommonJS. The following import statement will fail:
import data from './data.json'
It will produce a TypeError (Unknown file extension: .json).
To overcome this limitation, we can use again the module.createRequire utility:
import { createRequire } from 'module'
const require = createRequire(import.meta.url)
const data = require('./data.json')
console.log(data)
There is ongoing work to support JSON modules natively even in ESM, so we may not need to rely on createRequire() in the near future for this functionality.
- Learning PostgreSQL
- 體驗(yàn)設(shè)計(jì)原理:行為、情感和細(xì)節(jié)
- 華為HMS生態(tài)與應(yīng)用開發(fā)實(shí)戰(zhàn)
- MATLAB 2020 從入門到精通
- PySide GUI Application Development(Second Edition)
- Linux命令行與shell腳本編程大全(第4版)
- PySpark Cookbook
- JBoss:Developer's Guide
- 編程改變生活:用Python提升你的能力(進(jìn)階篇·微課視頻版)
- Python計(jì)算機(jī)視覺和自然語言處理
- Puppet:Mastering Infrastructure Automation
- ROS機(jī)器人編程實(shí)戰(zhàn)
- Spring Web Services 2 Cookbook
- 編寫高質(zhì)量代碼之Java(套裝共2冊(cè))
- Java EE 程序設(shè)計(jì)