You are viewing an old revision of this post, from November 23, 2022 @ 11:45:37. See below for differences between this version and the current revision.
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: JavaScript (javascript)
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)
}
Talvez outros ajustes sejam 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 para nós, isto foi um alívio e tanto!
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
Changes:
November 23, 2022 @ 11:45:37 | Current Revision | ||
---|---|---|---|
Content | |||
Unchanged: <!-- wp:paragraph --> | Unchanged: <!-- wp:paragraph --> | ||
Unchanged: <p>Aqui na Liferay, alguns dias atrás, necessitávamos utilizar o pacote <a href="https:/ /www.npmjs.com/package/p- map">p-map</a>. Só tinha um problema: esta aplicação em específico utilizava módulos no padrão <a href="https:/ /nodejs.org/docs/latest/api/ modules.html" >CommonJS</a>, e p-map utiliza <a href="https:/ /developer.mozilla.org/en- US/docs/Web/JavaScript/Guide/ Modules">módulos ES6</a>. Até algumas das melhores referências que encontrei (por exemplo, <a href="https:/ /reflectoring.io/ nodejs-modules- imports/">este post</a>) deixavam claro que não seria possível importar módulos ES6 a partir de CommonJS.</p> | Unchanged: <p>Aqui na Liferay, alguns dias atrás, necessitávamos utilizar o pacote <a href="https:/ /www.npmjs.com/package/p- map">p-map</a>. Só tinha um problema: esta aplicação em específico utilizava módulos no padrão <a href="https:/ /nodejs.org/docs/latest/api/ modules.html" >CommonJS</a>, e p-map utiliza <a href="https:/ /developer.mozilla.org/en- US/docs/Web/JavaScript/Guide/ Modules">módulos ES6</a>. Até algumas das melhores referências que encontrei (por exemplo, <a href="https:/ /reflectoring.io/ nodejs-modules- imports/">este post</a>) deixavam claro que não seria possível importar módulos ES6 a partir de CommonJS.</p> | ||
Unchanged: <!-- /wp:paragraph --> | Unchanged: <!-- /wp:paragraph --> | ||
Unchanged: <!-- wp:paragraph --> | Unchanged: <!-- wp:paragraph --> | ||
Deleted: <p>A boa notícia é que isto não é mais verdade! Usando <code>import</code> dinâmico, podemos carregar módulos ES6 a partir de CommonJS. Vejamos um exemplo.</p> | Added: <p>A boa notícia é que isto não é mais verdade! Usando <a href="https:/ /developer.mozilla.org/en- US/docs/Web/JavaScript/Reference/ Operators/import" ><code>import</code> dinâmico</a>, podemos carregar módulos ES6 a partir de CommonJS. Vejamos um exemplo.</p> | ||
Unchanged: <!-- /wp:paragraph --> | Unchanged: <!-- /wp:paragraph --> | ||
Unchanged: <!-- wp:paragraph --> | Unchanged: <!-- wp:paragraph --> | ||
Unchanged: <p>Neste <a href="https:/ /github.com/brandizzi/ es6commonjs/ ">projeto</a>, o arquivo <a href="https:/ /github.com/brandizzi/ es6commonjs/ blob/d7c3e3a69ef7828e6dcf714a5e83e77892294490/ importer.js"> importer.js</a> tenta utilizar <code>require()</code> para importar um módulo ES6:</p> | Unchanged: <p>Neste <a href="https:/ /github.com/brandizzi/ es6commonjs/ ">projeto</a>, o arquivo <a href="https:/ /github.com/brandizzi/ es6commonjs/ blob/d7c3e3a69ef7828e6dcf714a5e83e77892294490/ importer.js"> importer.js</a> tenta utilizar <code>require()</code> para importar um módulo ES6:</p> | ||
Unchanged: <!-- /wp:paragraph --> | Unchanged: <!-- /wp:paragraph --> | ||
Deleted: <!-- wp:code --> | Added: <!-- wp:code {"language":" javascript"} --> | ||
Unchanged: <pre class="wp-block- code"><code>const pmap = require('p-map'); | Unchanged: <pre class="wp-block- code"><code>const pmap = require('p-map'); | ||
Unchanged: exports.importer = () => { | Unchanged: exports.importer = () => { | ||
Unchanged: console.log('Yes, I could import p-map:', pmap); | Unchanged: console.log('Yes, I could import p-map:', pmap); | ||
Unchanged: }</code></pre> | Unchanged: }</code></pre> | ||
Unchanged: <!-- /wp:code --> | Unchanged: <!-- /wp:code --> | ||
Unchanged: <!-- wp:paragraph --> | Unchanged: <!-- wp:paragraph --> | ||
Unchanged: <p>Naturalmente, isto não funciona:</p> | Unchanged: <p>Naturalmente, isto não funciona:</p> | ||
Unchanged: <!-- /wp:paragraph --> | Unchanged: <!-- /wp:paragraph --> | ||
Deleted: <!-- wp:code --> | Added: <!-- wp:code {"language":"bash"} --> | ||
Unchanged: <pre class="wp-block- code"><code>$ node index.js | Unchanged: <pre class="wp-block- code"><code>$ node index.js | ||
Unchanged: internal/modules/ cjs/loader.js:1102 | Unchanged: internal/modules/ cjs/loader.js:1102 | ||
Unchanged: throw new ERR_REQUIRE_ESM(filename, parentPath, packageJsonPath); | Unchanged: throw new ERR_REQUIRE_ESM(filename, parentPath, packageJsonPath); | ||
Unchanged: ^ | Unchanged: ^ | ||
Unchanged: Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /home/adam/software/ es6commonjs/node_modules/ p-map/index.js | Unchanged: Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /home/adam/software/ es6commonjs/node_modules/ p-map/index.js | ||
Unchanged: require() of ES modules is not supported. | Unchanged: require() of ES modules is not supported. | ||
Unchanged: 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. | Unchanged: 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. | ||
Unchanged: 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. | Unchanged: 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. | ||
Unchanged: at new NodeError (internal/errors.js:322:7) | Unchanged: at new NodeError (internal/errors.js:322:7) | ||
Unchanged: at Object.Module._ extensions..js (internal/modules/ cjs/loader.js:1102:13) | Unchanged: at Object.Module._ extensions..js (internal/modules/ cjs/loader.js:1102:13) | ||
Unchanged: at Module.load (internal/modules/ cjs/loader.js:950:32) | Unchanged: at Module.load (internal/modules/ cjs/loader.js:950:32) | ||
Unchanged: at Function.Module._load (internal/modules/ cjs/loader.js:790:12) | Unchanged: at Function.Module._load (internal/modules/ cjs/loader.js:790:12) | ||
Unchanged: at Module.require (internal/modules/ cjs/loader.js:974:19) | Unchanged: at Module.require (internal/modules/ cjs/loader.js:974:19) | ||
Unchanged: at require (internal/modules/ cjs/helpers.js:101:18) | Unchanged: at require (internal/modules/ cjs/helpers.js:101:18) | ||
Unchanged: at Object.<anonymous> (/home/adam/software/ es6commonjs/importer.js:1:14) | Unchanged: at Object.<anonymous> (/home/adam/software/ es6commonjs/importer.js:1:14) | ||
Unchanged: at Module._compile (internal/modules/ cjs/loader.js:1085:14) | Unchanged: at Module._compile (internal/modules/ cjs/loader.js:1085:14) | ||
Unchanged: at Object.Module._ extensions..js (internal/modules/ cjs/loader.js:1114:10) | Unchanged: at Object.Module._ extensions..js (internal/modules/ cjs/loader.js:1114:10) | ||
Unchanged: at Module.load (internal/modules/ cjs/loader.js:950:32) { | Unchanged: at Module.load (internal/modules/ cjs/loader.js:950:32) { | ||
Unchanged: code: 'ERR_REQUIRE_ESM' | Unchanged: code: 'ERR_REQUIRE_ESM' | ||
Unchanged: } | Unchanged: } | ||
Unchanged: </code></pre> | Unchanged: </code></pre> | ||
Unchanged: <!-- /wp:code --> | Unchanged: <!-- /wp:code --> | ||
Unchanged: <!-- wp:paragraph --> | Unchanged: <!-- wp:paragraph --> | ||
Unchanged: <p>A solução é converter o <code>require()</code> em um <code>import</code> dinâmico. Mas tem um detalhe: <code>import</code> dinâmicos retornam uma <code>Promise</code>. Há várias maneiras de lidar com isso; a mais simples provavelmente é tornar nossa função assíncrona, como <a href="https:/ /github.com/brandizzi/ es6commonjs/ blob/be491a9/ importer.js">nessa versão</a>:</p> | Unchanged: <p>A solução é converter o <code>require()</code> em um <code>import</code> dinâmico. Mas tem um detalhe: <code>import</code> dinâmicos retornam uma <code>Promise</code>. Há várias maneiras de lidar com isso; a mais simples provavelmente é tornar nossa função assíncrona, como <a href="https:/ /github.com/brandizzi/ es6commonjs/ blob/be491a9/ importer.js">nessa versão</a>:</p> | ||
Unchanged: <!-- /wp:paragraph --> | Unchanged: <!-- /wp:paragraph --> | ||
Deleted: <!-- wp:code --> | Added: <!-- wp:code {"language":" javascript"} --> | ||
Unchanged: <pre class="wp-block- code"><code>exports.importer = async () => { | Unchanged: <pre class="wp-block- code"><code>exports.importer = async () => { | ||
Unchanged: const pmap = await import('p-map'); | Unchanged: const pmap = await import('p-map'); | ||
Unchanged: console.log('Yes, I could import p-map:', pmap); | Unchanged: console.log('Yes, I could import p-map:', pmap); | ||
Unchanged: }</code></pre> | Unchanged: }</code></pre> | ||
Unchanged: <!-- /wp:code --> | Unchanged: <!-- /wp:code --> | ||
Unchanged: <!-- wp:paragraph --> | Unchanged: <!-- wp:paragraph --> | ||
Unchanged: <p>Agora nossa pequena aplicação funciona!</p> | Unchanged: <p>Agora nossa pequena aplicação funciona!</p> | ||
Unchanged: <!-- /wp:paragraph --> | Unchanged: <!-- /wp:paragraph --> | ||
Deleted: <!-- wp:code --> | Added: <!-- wp:code {"language":"bash"} --> | ||
Unchanged: <pre class="wp-block- code"><code>$ node index.js | Unchanged: <pre class="wp-block- code"><code>$ node index.js | ||
Unchanged: ok | Unchanged: ok | ||
Unchanged: Yes, I could import p-map: [Module: null prototype] { | Unchanged: Yes, I could import p-map: [Module: null prototype] { | ||
Unchanged: AbortError: [class AbortError extends Error], | Unchanged: AbortError: [class AbortError extends Error], | ||
Unchanged: default: [AsyncFunction: pMap], | Unchanged: default: [AsyncFunction: pMap], | ||
Unchanged: pMapSkip: Symbol(skip) | Unchanged: pMapSkip: Symbol(skip) | ||
Unchanged: }</code></pre> | Unchanged: }</code></pre> | ||
Unchanged: <!-- /wp:code --> | Unchanged: <!-- /wp:code --> | ||
Unchanged: <!-- wp:paragraph --> | Unchanged: <!-- wp:paragraph --> | ||
Deleted: <p> | Added: <p>Outros ajustes podem ser necessários; eu mesmo precisei ajustar as configurações do <a href="https:/ /stackoverflow.com/questions/ 47815775/dynamic-imports- for-code-splitting-cause- eslint-parsing- error-import" >eslint</a>. O importante é que isto é possível. E não é uma gambiarra: <a href="https:/ /nodejs.org/api/ esm.html#import- expressions">a própria documentação de Node recomenda essa abordagem</a>.</p> | ||
Unchanged: <!-- /wp:paragraph --> | Unchanged: <!-- /wp:paragraph --> | ||
Unchanged: <!-- wp:paragraph --> | Unchanged: <!-- wp:paragraph --> | ||
Deleted: <p>Então, não se assuste com informações desatualizadas: você <em>não</em> vai precisar reescrever sua aplicação toda como módulos ES 6 | Added: <p>Então, não se assuste com informações desatualizadas: você <em>não</em> vai precisar reescrever sua aplicação toda como módulos ES 6, ao menos por enquanto.</p> | ||
Unchanged: <!-- /wp:paragraph --> | Unchanged: <!-- /wp:paragraph --> |
Note: Spaces may be added to comparison text to allow better line wrapping.