Aqui na Liferay, alguns dias atrás, necessitávamos utilizar o pacote p-map. Só tinha um problema: esta aplicação em específico utilizava módulos no padrão CommonJS, e p-map utiliza módulos ES6. Até algumas das melhores referências que encontrei (por exemplo, este post) deixavam claro que não seria possível importar módulos ES6 a partir de CommonJS.
A boa notícia é que isto não é mais verdade! Usando import
dinâmico, podemos carregar módulos ES6 a partir de CommonJS. Vejamos um exemplo.
Neste projeto, o arquivo importer.js tenta utilizar require()
para importar um módulo ES6:
const pmap = require('p-map');
exports.importer = () => {
console.log('Yes, I could import p-map:', pmap);
}
Code language: JavaScript (javascript)
Naturalmente, isto não funciona:
$ node index.js
internal/modules/cjs/loader.js:1102
throw new ERR_REQUIRE_ESM(filename, parentPath, packageJsonPath);
^
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /home/adam/software/es6commonjs/node_modules/p-map/index.js
require() of ES modules is not supported.
require() of /home/adam/software/es6commonjs/node_modules/p-map/index.js from /home/adam/software/es6commonjs/importer.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /home/adam/software/es6commonjs/node_modules/p-map/package.json.
at new NodeError (internal/errors.js:322:7)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1102:13)
at Module.load (internal/modules/cjs/loader.js:950:32)
at Function.Module._load (internal/modules/cjs/loader.js:790:12)
at Module.require (internal/modules/cjs/loader.js:974:19)
at require (internal/modules/cjs/helpers.js:101:18)
at Object.<anonymous> (/home/adam/software/es6commonjs/importer.js:1:14)
at Module._compile (internal/modules/cjs/loader.js:1085:14)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
at Module.load (internal/modules/cjs/loader.js:950:32) {
code: 'ERR_REQUIRE_ESM'
}
Code language: Bash (bash)
A solução é converter o require()
em um import
dinâmico. Mas tem um detalhe: import
dinâmicos retornam uma Promise
. Há várias maneiras de lidar com isso; a mais simples provavelmente é tornar nossa função assíncrona, como nessa versão:
exports.importer = async () => {
const pmap = await import('p-map');
console.log('Yes, I could import p-map:', pmap);
}
Code language: JavaScript (javascript)
Agora nossa pequena aplicação funciona!
$ node index.js
ok
Yes, I could import p-map: [Module: null prototype] {
AbortError: [class AbortError extends Error],
default: [AsyncFunction: pMap],
pMapSkip: Symbol(skip)
}
Code language: Bash (bash)
Outros ajustes podem ser necessários; eu mesmo precisei ajustar as configurações do eslint. O importante é que isto é possível. E não é uma gambiarra: a própria documentação de Node recomenda essa abordagem.
Então, não se assuste com informações desatualizadas: você não vai precisar reescrever sua aplicação toda como módulos ES 6, ao menos por enquanto.
Post Revisions:
- March 20, 2023 @ 23:32:02 [Current Revision] by brandizzi
- March 20, 2023 @ 23:32:02 by brandizzi
- November 23, 2022 @ 12:07:14 by brandizzi
- November 23, 2022 @ 11:45:37 by brandizzi