Criando um Pacote NPM com Suporte a CommonJS e ESM usando Rollup

marcelolourenco

Marcelo Lourenço

Posted on October 14, 2024

Criando um Pacote NPM com Suporte a CommonJS e ESM usando Rollup

Neste post, vamos explorar como criar um pacote NPM com suporte a CommonJS (CJS) e ECMAScript Modules (ESM) usando Rollup.

Rollup é um bundler JavaScript ideal para criar bibliotecas e pacotes, pois ele gera bundles de código altamente otimizados, que podem ser facilmente usados em diferentes ambientes.

Estrutura do projeto:

my-npm-package/
├── src/
│   ├── index.js
|   └── utils
|       ├──math.js
|       └──string.js
├── rollup.config.js
└── package.json
Enter fullscreen mode Exit fullscreen mode

1. Configurando o Projeto

Comece criando um novo diretório para o seu pacote NPM. Dentro do diretório, execute o comando:

npm init -y
Enter fullscreen mode Exit fullscreen mode

Isso irá gerar um arquivo package.json básico.

Atualize o arquivo package.json com as seguintes informações:

{
  "name": "my-npm-package",
  "version": "1.0.0",
  "description": "",
  "type": "module",
  "main": "dist/index.cjs",
  "module": "dist/index.mjs",
  "scripts": {
    "build": "rollup -c",
    "dev": "rollup -c --watch"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/your-username/my-npm-package.git"
  },
  "author": "",
  "license": "MIT"
}
Enter fullscreen mode Exit fullscreen mode

Explicando as propriedades:

  • name: Nome do pacote NPM.
  • version: Versão do pacote.
  • description: Descrição do pacote.
  • main: Define o arquivo principal para projetos CommonJS.
  • module: Define o arquivo principal para projetos ESM.
  • scripts: Define scripts para build e desenvolvimento.
  • repository: Define o repositório do pacote.
  • author: Nome do autor do pacote.
  • license: Licença do pacote.

Em seguida, instale as dependências necessárias:

npm install rollup @rollup/plugin-commonjs @rollup/plugin-node-resolve
Enter fullscreen mode Exit fullscreen mode

Explicando as dependências:

  • rollup: Ferramenta de empacotamento de módulos.
  • rollup-plugin-commonjs: Plugin Rollup para lidar com módulos CommonJS.
  • rollup-plugin-node-resolve: Plugin Rollup para resolver dependências de módulos do Node.js.

2. Criando a Pasta src

Crie uma pasta chamada src dentro do diretório do projeto.

Dentro de src, crie um arquivo index.js.

// src/index.js
import { add } from './utils/math.js';
import { toUpperCase } from './utils/string.js';

export function calculate() {
  const result = add(10, 20);
  return `Result: ${result}, UpperCase: ${toUpperCase('hello')}`;
}
Enter fullscreen mode Exit fullscreen mode

Dentro de src, crie o subdiretório utils.

Dentro do subdiretório utils, crie os aquivos:
math.js

// src/utils/math.js
export function add(a, b) {
  return a + b;
}
Enter fullscreen mode Exit fullscreen mode

string.js

// src/utils/string.js
export function toUpperCase(str) {
  return str.toUpperCase();
}
Enter fullscreen mode Exit fullscreen mode

3. Criando o Arquivo rollup.config.js.

Crie um arquivo rollup.config.js com a configuração do Rollup.

O Rollup tem 2 opções de configurações de saída:

  • A primeira: Todo o código em único arquivo de saída.
  • A segunda: Utilizando o preserveModules para manter a estrutura de módulos.

3.1 Arquivo rollup.config.js sem preservar a estrutura de módulo

O Rollup, por padrão, combina todos os módulos em um único arquivo de saída. Isso significa que todos os seus módulos, incluindo seus próprios e seus dependentes, são mesclados em um único arquivo JavaScript.

// rollup.config.js
import commonjs from 'rollup-plugin-commonjs';
import resolve from 'rollup-plugin-node-resolve';

export default [
  {
    input: 'src/index.js', // Arquivo principal de entrada
    output: {
      file: 'dist/index.cjs', // Diretório de saída para CommonJS
      format: 'cjs',
      sourcemap: true,
    },
    plugins: [
      resolve(),
      commonjs(),
    ],
  },
  {
    input: 'src/index.js', // Arquivo principal de entrada
    output: {
      file: 'dist/index.mjs', // Diretório de saída para ES Modules
      format: 'es',
      sourcemap: true,
    },
    plugins: [
      resolve(),  // Resolve módulos de node_modules
      commonjs()  // Converte pacotes CommonJS para ESModules
    ],
  },
];
Enter fullscreen mode Exit fullscreen mode

Explicando as configurações:

  • input: Define o arquivo de entrada para o Rollup.
  • output: Define o arquivo de saída e o formato de saída.
  • format: Define o formato do módulo (ESM ou CommonJS).
  • plugins: Define os plugins que serão utilizados no Rollup.

3.2 Arquivo rollup.config.js preservando a estrutura de módulo

O Rollup mantém a estrutura de módulos do seu código original. Cada módulo do seu projeto será empacotado em seu próprio arquivo.

// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';

export default {
  input: './src/index.js',  // Arquivo principal de entrada

  output: [
    {
      dir: 'dist/cjs', // Diretório de saída para CommonJS
      format: 'cjs',
      entryFileNames: '[name].cjs', // Mantém o nome do arquivo original
      exports: 'auto',
      preserveModules: true, // Preserva a estrutura dos módulos
      preserveModulesRoot: 'src', // Diretório base que será mantido
    },
    {
      dir: 'dist/mjs', // Diretório de saída para ES Modules
      format: 'es',
      entryFileNames: '[name].mjs',
      preserveModules: true,
      preserveModulesRoot: 'src',
    }
  ],
  plugins: [
    resolve(),  // Resolve módulos de node_modules
    commonjs()  // Converte pacotes CommonJS para ESModules
  ]
};
Enter fullscreen mode Exit fullscreen mode

Explicando as configurações:

  • entryFileNames: Define um padrão para os nomes dos arquivos de saída, usando placeholders:
    • [name]: Substituído pelo nome do módulo.
    • [hash]: Substituído por um hash único para o arquivo.
    • [format]: Substituído pelo formato do módulo (esm ou cjs).
  • preserveModules: Preserva a estrutura de módulos original do código. Se true, cada módulo será empacotado em seu próprio arquivo.
  • preserveModulesRoot: Define o diretório raiz dos módulos a serem preservados.

3.2.1 Neste caso, altere essas linhas no package.json:

"main": "dist/cjs/index.cjs",
"module": "dist/mjs/index.mjs",
Enter fullscreen mode Exit fullscreen mode

4. Compilando e Publicando o Pacote

Execute o comando npm run build para compilar o seu pacote. Isso irá gerar os arquivos compilados em dist/.

Em seguida, publique o pacote no npm usando o comando npm publish.

5. Usando o Pacote

Agora você pode usar o pacote NPM que criou em outros projetos.

  • Exemplo em um projeto CommonJS:
const { calculate } = require('my-npm-package');
console.log(calculate()); // "Result: 30, UpperCase: HELLO"
Enter fullscreen mode Exit fullscreen mode
  • Exemplo em um projeto ESM (quando o package.json tem o "type": "module"):
import { calculate } from 'my-npm-package';
console.log(calculate()); // "Result: 30, UpperCase: HELLO"
Enter fullscreen mode Exit fullscreen mode

Conclusão

Criar um pacote NPM com suporte a CommonJS e ESM é simples usando o Rollup. Ao seguir as etapas descritas neste post, você pode construir um pacote flexível e reutilizável que atenda às necessidades de diferentes projetos.

💖 💪 🙅 🚩
marcelolourenco
Marcelo Lourenço

Posted on October 14, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related