DEV Community

romulospl
romulospl

Posted on

Criando monorepo com biblioteca reutilizavel, usando PNPM (React + TypeScript)

Introdução:

Neste artigo aborda a criação de um monorepo para desenvolvimento de projetos, com destaque para a configuração de um workspace e a publicação de um pacote no GitHub Package Registry. Demonstramos também como utilizar esse pacote em um novo projeto externo ao monorepo, fornecendo uma visão abrangente do desenvolvimento modular e colaborativo.

Passo 1: Configurando o Ambiente Inicial

Vamos começar criando o diretório do projeto e inicializando nosso workspace monorepo usando pnpm. Primeiro, crie uma nova pasta para o projeto no local de sua preferência. No exemplo abaixo, criaremos a pasta no diretório home:

mkdir ~/monorepo-project
Enter fullscreen mode Exit fullscreen mode

Essa pasta servirá como o workspace do nosso monorepo. Em seguida, navegue até essa pasta e inicialize um novo projeto Node.js com pnpm:

cd ~/monorepo-project
pnpm init
Enter fullscreen mode Exit fullscreen mode

Após inicializar o projeto, vamos configurar o controle de versão com Git e criar um arquivo .gitignore para ignorar a pasta node_modules:

git init
echo -e "node_modules" > .gitignore
Enter fullscreen mode Exit fullscreen mode

O comando git init inicializa um novo repositório Git no diretório atual, e o comando echo -e "node_modules" > .gitignore cria um arquivo .gitignore com a entrada node_modules, que informa ao Git para ignorar essa pasta, evitando que ela seja incluída nos commits.

Finalmente, vamos configurar o projeto para usar módulos ES6 alterando o tipo de módulo no arquivo package.json:

npm pkg set type="module"
Enter fullscreen mode Exit fullscreen mode

Isso adiciona a seguinte linha ao seu package.json:

{
....
  "type": "module"
}

Enter fullscreen mode Exit fullscreen mode

A configuração "type": "module" permite que você use a sintaxe de módulos ES6 (import/export) no seu projeto Node.js.

Passo 2: Estruturando o Projeto

Agora que temos o ambiente inicial configurado, vamos estruturar nosso monorepo criando as pastas necessárias e inicializando um projeto de biblioteca de componentes.

Primeiro, crie duas pastas chamadas packages e apps:

mkdir packages apps
Enter fullscreen mode Exit fullscreen mode

A pasta packages será usada para armazenar pacotes reutilizáveis, como nossa biblioteca de componentes, e a pasta apps conterá nossos aplicativos.

Criando o Projeto de Biblioteca de Componentes (UI Kit)

Dentro da pasta packages, vamos criar um projeto de biblioteca de componentes chamado uikit usando o Vite. Para isso, execute os seguintes comandos:

cd packages
pnpm create vite
Enter fullscreen mode Exit fullscreen mode

Durante a criação do projeto com o Vite, você será solicitado a fornecer algumas informações, como o nome do projeto e o template a ser usado. Siga as instruções e escolha as opções apropriadas para o seu projeto de biblioteca de componentes.

Image description

Depois de concluir a criação do projeto, sua estrutura de diretórios deverá se parecer com isto:

monorepo-project/
  ├── packages/
  │   └── uikit/
  ├── apps/
  ├── package.json
  ├── .gitignore
  ├── pnpm-lock.yaml
Enter fullscreen mode Exit fullscreen mode

Passo 3: Criando o Componente de UI

Agora que temos nosso projeto de biblioteca de componentes configurado, vamos criar um simples componente de botão dentro do uikit.

Primeiro, navegue até a pasta uikit:

cd uikit
pnpm install
Enter fullscreen mode Exit fullscreen mode

Em seguida, dentro da pasta src do projeto uikit, crie a estrutura de diretórios components/Button:

mkdir -p src/components/Button
Enter fullscreen mode Exit fullscreen mode

Dentro dessa pasta Button, crie um arquivo chamado index.tsx e adicione o seguinte código:

// src/components/Button/index.tsx
export default function ButtonTeste() {
  return <div style={{ backgroundColor: 'green', borderRadius: '25px', padding: '10px' }}>Button</div>
}

Enter fullscreen mode Exit fullscreen mode

Este código define um componente React simples chamado ButtonTeste que renderiza um botão estilizado com uma cor de fundo verde, bordas arredondadas e padding.

Após criar o componente, sua estrutura de diretórios deve se parecer com isto:

cssCopiar código
monorepo-project/
  ├── packages/
  │   └── uikit/
  │       └── src/
  │           └── components/
  │               └── Button/
  │                   └── index.tsx
  ├── apps/
  ├── package.json
  ├── .gitignore
  ├── pnpm-lock.yaml
Enter fullscreen mode Exit fullscreen mode

Passo 4: Configurando o Vite para Modo Biblioteca

Para que nosso projeto uikit funcione como uma biblioteca, precisamos ajustar a configuração do Vite. Por padrão, o Vite busca um arquivo index.html como ponto de entrada no modo de aplicação. No entanto, queremos que ele procure main.ts para exportar nossos componentes.

Instalando o Plugin DTS

Primeiro, vamos instalar o plugin DTS, que gera arquivos de declaração (*.d.ts) a partir de arquivos .ts(x) quando o Vite está configurado no modo biblioteca. Execute o seguinte comando dentro da pasta uikit:

pnpm add -D vite-plugin-dts
Enter fullscreen mode Exit fullscreen mode

Configurando o Vite

Se o arquivo vite.config.ts não existir, crie-o na raiz do projeto uikit e adicione o seguinte código:

// vite.config.ts
import { defineConfig } from 'vite';
import { resolve } from 'path';
import dts from 'vite-plugin-dts';

export default defineConfig({
  build: {
    lib: {
      entry: resolve(__dirname, 'src/main.ts'),
      formats: ['es', 'cjs'],
      fileName: (format) => `main.${format}.js`,
    },
    rollupOptions: {
      external: ['react', 'react-dom'],
      output: {
        globals: {
          react: 'React',
          'react-dom': 'ReactDOM',
        },
      },
    },
  },
  resolve: {
    alias: {
      src: resolve(__dirname, 'src/'),
    },
  },
  plugins: [
    dts({
      tsconfigPath: './tsconfig.json', // Caminho para o arquivo tsconfig.json
      outDir: 'dist', // Diretório de saída dos arquivos de definição de tipos
    }),
  ],
});

Enter fullscreen mode Exit fullscreen mode
  • Se der erro na importação do resolve do pacote ‘path’ basta dar o seguinte comando dentro da pasta uikit: pnpm install --save-dev @types/node

Criando o Arquivo main.ts

Agora, crie o arquivo main.ts dentro da pasta src que será o responsável exportar nossos componentes:

touch src/main.ts
Enter fullscreen mode Exit fullscreen mode

Adicione o seguinte conteúdo ao arquivo main.ts para exportar o componente ButtonTeste:

// src/main.ts
import ButtonTeste from './components/Button';
export { ButtonTeste } 
Enter fullscreen mode Exit fullscreen mode

Após essas configurações, sua estrutura de diretórios deve se parecer com isto:

monorepo-project/
  ├── packages/
  │   └── uikit/
  │       ├── src/
  │       │   ├── components/
  │       │   │   └── Button/
  │       │   │       └── index.tsx
  │       │   └── main.ts
  │       └── vite.config.ts
  ├── apps/
  ├── package.json
  ├── .gitignore
  ├── pnpm-lock.yaml
Enter fullscreen mode Exit fullscreen mode

Passo 5: Configurando o package.json para Suporte a CommonJS e ES Modules

Para garantir que nossa biblioteca uikit suporte tanto CommonJS quanto ES Modules, precisamos atualizar o package.json com as entradas apropriadas para os pontos de entrada do módulo e as declarações de tipos.

Atualizando o package.json

Abra o arquivo package.json do projeto uikit e adicione as seguintes configurações:

{
  ...
  "main": "./dist/main.es.js",
  "module": "./dist/main.es.js",
  "types": "./dist/main.d.ts",
  "exports": {
    ".": {
      "import": "./dist/main.es.js",
      "require": "./dist/main.es.js",
      "types": "./dist/main.d.ts"
    }
  },
  "files": [
    "dist"
  ],
  ...
}

Enter fullscreen mode Exit fullscreen mode

Detalhes do arquivo package.json:

  • "main": "./dist/main.cjs.js": Especifica o ponto de entrada para consumidores CommonJS.
  • "module": "./dist/main.js": Especifica o ponto de entrada para consumidores ES Modules.
  • "types": "./dist/main.d.ts": Especifica o arquivo de declarações de tipos TypeScript.
  • "exports": Define como os diferentes módulos podem ser importados.
    • "import": Usado por ES Modules.
    • "require": Usado por CommonJS.
    • "types": Define o caminho para os arquivos de declarações de tipos.
  • "files": Especifica quais arquivos devem ser incluídos no pacote publicado. Neste caso, apenas a pasta dist será incluída.
  • "scripts": Adiciona um script de build para compilar a biblioteca usando Vite.

Passo 6: Criando o Projeto Web App e Configurando o Workspace

Agora vamos criar o projeto web-app, que fará uso da nossa biblioteca de componentes uikit, dentro do mesmo repositório.

Criando o Projeto Web App

Navegue até a pasta apps dentro da raiz do projeto monorepo-project e crie o projeto web-app usando o Vite:

# dentro de monorepo-project/apps execute:
pnpm create vite
Enter fullscreen mode Exit fullscreen mode

Image description

entre dentro da pasta web-app execute pnpm install para instalar as dependências.

Configurando o Workspace

Após criar o projeto web-app, precisamos configurar um workspace para gerenciar todos os projetos dentro do mesmo repositório.

Volte para a pasta raiz do monorepo-project e crie um arquivo chamado pnpm-workspace.yaml:

cd ..
touch pnpm-workspace.yaml
Enter fullscreen mode Exit fullscreen mode

Dentro desse arquivo, insira o seguinte conteúdo:

packages:
  - 'apps/*'
  - 'packages/*'
Enter fullscreen mode Exit fullscreen mode

Essa configuração informa ao pnpm para reconhecer os diretórios apps e packages como parte do workspace, permitindo que eles sejam gerenciados em conjunto.
Após realizar essas etapas, sua estrutura de diretórios deve se parecer com isto:


monorepo-project/
  ├── packages/
  │   └── uikit/
  │       ├── src/
  │       │   ├── components/
  │       │   │   └── Button/
  │       │   │       └── index.tsx
  │       │   └── main.ts
  │       ├── tsup.config.ts
  │       └── package.json
  ├── apps/
  │   └── web-app/
  │       ├── src/
  │       ├── package.json
  ├── package.json
  ├── pnpm-lock.yaml
  ├── pnpm-workspace.yaml
  ├── .gitignore


Enter fullscreen mode Exit fullscreen mode

Com isso, temos o projeto web-app criado e o workspace configurado para gerenciar todos os projetos dentro do mesmo repositório.

Passo 7: Instalando e Configurando o tsup

O tsup é uma ferramenta rápida para transpilar arquivos TypeScript em JavaScript. Ele simplifica o processo de configuração e execução, facilitando a compilação de código TypeScript para uso em projetos JavaScript.

Instalando o tsup

Para instalar o tsup, execute o seguinte comando dentro da pasta uikit:

pnpm add tsup -D
Enter fullscreen mode Exit fullscreen mode

Criando o Arquivo de Configuração tsup.config.ts

Agora, crie o arquivo tsup.config.ts na raiz do projeto uikit e adicione o seguinte código:

// tsup.config.ts
import { defineConfig } from 'tsup';

export default defineConfig({
  entry: ['src/main.ts'],
  format: ['cjs', 'esm'],
  dts: true,
  sourcemap: true,
  clean: true,
  outDir: 'dist',
  external: ['react', 'react-dom'],
});

Enter fullscreen mode Exit fullscreen mode

detalhes o tsup.config.ts

  • entry: Especifica o arquivo de entrada ou uma lista de arquivos de entrada para transpilação.
  • format: Define os formatos de saída desejados, neste caso, CommonJS (cjs) e ES Module (esm).
  • dts: Habilita a geração de arquivos de definição de tipos TypeScript.
  • sourcemap: Habilita a geração de sourcemaps para depuração.
  • clean: Limpa o diretório de saída antes de compilar.
  • outDir: Especifica o diretório de saída dos arquivos transpilados.
  • external: Lista de módulos que serão considerados externos e não incluídos no pacote.

Após essas configurações, sua estrutura de diretórios deve se parecer com isto:

cssCopiar código
monorepo-project/
  ├── packages/
  │   └── uikit/
  │       ├── src/
  │       │   ├── components/
  │       │   │   └── Button/
  │       │   │       └── index.tsx
  │       │   └── main.ts
  │       ├── tsup.config.ts
  │       └── package.json
  ├── apps/
  ├── package.json
  ├── .gitignore
  ├── pnpm-lock.yaml

Enter fullscreen mode Exit fullscreen mode

Passo 8: Configurando o Web App para Usar o UI Kit

Agora vamos configurar o projeto web-app para utilizar o uikit que criamos anteriormente.

Adicionando o UI Kit como Dependência

Abra o arquivo package.json do projeto web-app e adicione o uikit como uma dependência:

{
  "name": "web-app",
  "version": "1.0.0",
  "dependencies": {
    "uikit": "workspace:*"
  }
}
Enter fullscreen mode Exit fullscreen mode

Execute o comando pnpm install na pasta web-app para que as dependências sejam instaladas e o uikit seja reconhecido pelo projeto.

Atualizando o App.tsx

Atualize o arquivo App.tsx do projeto web-app para importar e utilizar o componente ButtonTeste do uikit:

// web-app/src/App.tsx
import { ButtonTeste } from "uikit";

function App() {
  return (
    <>
      <ButtonTeste />
    </>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Compilando o UI Kit

Antes de iniciar o servidor de desenvolvimento, certifique-se de compilar o uikit. Navegue até a pasta uikit e execute o comando pnpm build.

Iniciando o Servidor de Desenvolvimento

Por fim, execute o comando pnpm run dev dentro da pasta web-app para iniciar o servidor de desenvolvimento e visualizar o botão na tela.

cd monorepo-project/apps/web-app
pnpm run dev
Enter fullscreen mode Exit fullscreen mode

Isso iniciará o servidor de desenvolvimento e você poderá acessar o projeto web-app em seu navegador para visualizar o botão do UI Kit.

Passo 9: Publicando o UI Kit no GitHub Package Registry

Agora vamos publicar nosso pacote uikit no GitHub Package Registry.

Configurando o Arquivo .npmrc

Crie um arquivo chamado .npmrc na raiz do projeto uikit e adicione o seguinte conteúdo, substituindo seuNomeDeUsuario pelo seu nome de usuário do GitHub e SeuToken pelo seu token de acesso (certifique-se de que seu token tenha permissões para criar pacotes no GitHub):

@seuNomeDeUsuario:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=SeuToken
Enter fullscreen mode Exit fullscreen mode

Criando o Arquivo .npmignore

Também na raiz do projeto uikit, crie um arquivo chamado .npmignore com o seguinte conteúdo:

# Ignore everything
*

# Mas não ignore a pasta dist
!dist

# Você também pode querer incluir o package.json e outros arquivos importantes
!package.json
!README.md

Enter fullscreen mode Exit fullscreen mode

Modificando o package.json

Abra o arquivo package.json do projeto uikit e modifique o nome do pacote e o atributo private. Seu package.json deve ficar semelhante a isso:

{
  "name": "@seuNomeDeUsuario/nomeDoPacote",
  "private": false,
  ...
}

Enter fullscreen mode Exit fullscreen mode

Substitua seuNomeDeUsuario pelo seu nome de usuário do GitHub e nomeDoPacote pelor exemplo o meu projeto fica da seguinte forma:

{
  "name": "@romulospl/uikit",
  "private": false,
  ...
}
Enter fullscreen mode Exit fullscreen mode

Publicando o Pacote

Agora estamos prontos para publicar nosso pacote. Execute o seguinte comando na raiz do projeto uikit:
npm publish --registry=https://npm.pkg.github.com

Isso irá publicar o pacote uikit no GitHub Package Registry.

Após publicar o pacote uikit no GitHub Package Registry, é importante verificar se a publicação foi realizada com sucesso.

Acessando o GitHub Package Registry

Acesse o seguinte link em seu navegador, substituindo seuNomeDeUsuario pelo seu nome de usuário do GitHub:

https://github.com/seuNomeDeUsuario?tab=packages

Verificando o Pacote Publicado

Na página dos pacotes do seu perfil do GitHub, você deve ser capaz de ver o pacote uikit listado. Isso confirma que o pacote foi publicado com sucesso no GitHub Package Registry.
Verifique se todas as informações estão corretas e se o pacote está disponível para uso.

Passo 10: Criando o Projeto use-component e Utilizando o UI Kit

Agora vamos criar um novo projeto chamado use-component fora do monorepo-project e utilizá-lo para demonstrar o uso do nosso pacote uikit do GitHub Package Registry.

Criando o Projeto use-component

Na pasta de sua preferência (por exemplo, na sua pasta pessoal), execute o seguinte comando para criar o projeto use-component usando Vite:

pnpm create vite use-component
Enter fullscreen mode Exit fullscreen mode

Em seguida, entre na pasta do projeto e execute pnpm install para instalar as dependências:

cd use-component
pnpm install
Enter fullscreen mode Exit fullscreen mode

Instalando o Pacote uikit do GitHub Package Registry

Acesse o GitHub e vá para a página dos seus pacotes, substituindo seuNomeDeUsuario pelo seu nome de usuário do GitHub:
https://github.com/seuNomeDeUsuario?tab=packages

Clique no pacote uikit para acessar sua página. Lá você encontrará o comando para instalar o pacote.

Image description

Copie o comando, substituindo @romulospl/uikit pelo nome do seu pacote e 0.0.0 pela versão desejada.

Em seguida, crie um arquivo chamado .npmrc na raiz do projeto use-component e adicione a seguinte linha, substituindo seuNomeDeUsuario pelo seu nome de usuário do GitHub:

@seuNomeDeUsuario:registry = https://npm.pkg.github.com
Enter fullscreen mode Exit fullscreen mode

Depois disso, cole o comando que você copiou anteriormente para instalar o pacote uikit, substituindo as informações necessárias.

pnpm install @seuNomeDeUsuario/uikit@0.0.0
Enter fullscreen mode Exit fullscreen mode

Utilizando o Componente do UI Kit

Agora que o pacote uikit está instalado, vamos utilizá-lo no arquivo App.tsx dentro da pasta src do projeto use-component.

Modifique o arquivo App.tsx para importar e utilizar o componente ButtonTeste do pacote uikit:

// use-component/src/App.tsx
import './App.css';
import { ButtonTeste } from '@seuNomeDeUsuario/uikit';

function App() {
  return (
    <>
      <ButtonTeste />
    </>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Executando a Aplicação

Agora execute a aplicação com o comando pnpm run dev e você verá o botão do UI Kit em funcionamento na tela.

Se você verificar a pasta node_modules dentro do projeto use-component, verá uma pasta @seuNomeDeUsuario (por exemplo, @romulospl). Dentro dessa pasta, há uma pasta uikit, contendo apenas a pasta dist do projeto e o arquivo package.json com as configurações de entrada e exportação.

Image description

Link para o repositório monorepo-project

Top comments (3)

Collapse
 
thayn_fagundes profile image
Thayná Fagundes

Incrível

Collapse
 
matheussouto profile image
Matheus Souto

Excelente tutorial. Muito útil!

Collapse
 
keillaarruda profile image
Keilla Arruda

Arrasooou !