JavaScript Avançado

Como Usar TypeScript Compiler API: tsconfig Avançado e Project References em Produção

8 min de leitura

Como Usar TypeScript Compiler API: tsconfig Avançado e Project References em Produção

TypeScript Compiler API: tsconfig Avançado e Project References Entendendo o tsconfig.json Avançado O arquivo é muito mais que um simples arquivo de configuração. Ele controla como o compilador TypeScript processa seu código, otimiza builds e gerencia dependências entre projetos. Quando trabalhamos com aplicações grandes, dominar as opções avançadas é essencial para manter a performance e a qualidade do código. As opções mais críticas para projetos profissionais incluem , , e . A opção permite que o TypeScript armazene em cache informações de compilação anteriores, acelerando recompilações. Já prepara seu projeto para ser referenciado por outros, essencial quando usamos Project References. Project References: Dividindo Projetos Grandes Project References permitem que você organize código TypeScript em múltiplos projetos compilados independentemente. Isso é revolucionário para monorepos e aplicações complexas onde diferentes partes do código têm ciclos de compilação diferentes. Quando você ativa e em um , esse projeto pode ser referenciado por outros. A chave está em usar no arquivo raiz para informar

<h2>TypeScript Compiler API: tsconfig Avançado e Project References</h2>

<h3>Entendendo o tsconfig.json Avançado</h3>

<p>O arquivo <code>tsconfig.json</code> é muito mais que um simples arquivo de configuração. Ele controla como o compilador TypeScript processa seu código, otimiza builds e gerencia dependências entre projetos. Quando trabalhamos com aplicações grandes, dominar as opções avançadas é essencial para manter a performance e a qualidade do código.</p>

<p>As opções mais críticas para projetos profissionais incluem <code>incremental</code>, <code>composite</code>, <code>declaration</code> e <code>moduleResolution</code>. A opção <code>incremental</code> permite que o TypeScript armazene em cache informações de compilação anteriores, acelerando recompilações. Já <code>composite</code> prepara seu projeto para ser referenciado por outros, essencial quando usamos Project References.</p>

<pre><code class="language-json">{

&quot;compilerOptions&quot;: {

&quot;target&quot;: &quot;ES2020&quot;,

&quot;module&quot;: &quot;ESNext&quot;,

&quot;lib&quot;: [&quot;ES2020&quot;],

&quot;declaration&quot;: true,

&quot;declarationMap&quot;: true,

&quot;sourceMap&quot;: true,

&quot;outDir&quot;: &quot;./dist&quot;,

&quot;rootDir&quot;: &quot;./src&quot;,

&quot;strict&quot;: true,

&quot;esModuleInterop&quot;: true,

&quot;skipLibCheck&quot;: true,

&quot;forceConsistentCasingInFileNames&quot;: true,

&quot;resolveJsonModule&quot;: true,

&quot;incremental&quot;: true,

&quot;tsBuildInfoFile&quot;: &quot;./.tsbuildinfo&quot;,

&quot;composite&quot;: true,

&quot;declaration&quot;: true

},

&quot;include&quot;: [&quot;src/*/&quot;],

&quot;exclude&quot;: [&quot;node_modules&quot;, &quot;dist&quot;, &quot;*/.spec.ts&quot;]

}</code></pre>

<h3>Project References: Dividindo Projetos Grandes</h3>

<p>Project References permitem que você organize código TypeScript em múltiplos projetos compilados independentemente. Isso é revolucionário para monorepos e aplicações complexas onde diferentes partes do código têm ciclos de compilação diferentes.</p>

<p>Quando você ativa <code>composite: true</code> e <code>declaration: true</code> em um <code>tsconfig.json</code>, esse projeto pode ser referenciado por outros. A chave está em usar <code>references</code> no arquivo raiz para informar ao compilador as dependências entre projetos.</p>

<pre><code class="language-json">{

&quot;compilerOptions&quot;: {

&quot;target&quot;: &quot;ES2020&quot;,

&quot;module&quot;: &quot;ESNext&quot;,

&quot;outDir&quot;: &quot;./dist&quot;,

&quot;rootDir&quot;: &quot;./src&quot;,

&quot;strict&quot;: true,

&quot;composite&quot;: true,

&quot;declaration&quot;: true,

&quot;declarationMap&quot;: true,

&quot;incremental&quot;: true,

&quot;tsBuildInfoFile&quot;: &quot;./.tsbuildinfo&quot;

},

&quot;include&quot;: [&quot;src/*/&quot;],

&quot;references&quot;: [

{ &quot;path&quot;: &quot;../common&quot; },

{ &quot;path&quot;: &quot;../api&quot; }

]

}</code></pre>

<p>A estrutura de um monorepo típico seria:</p>

<pre><code>monorepo/

├── tsconfig.json (raiz)

├── common/

│ ├── tsconfig.json (composite: true)

│ └── src/

│ ├── types.ts

│ └── utils.ts

├── api/

│ ├── tsconfig.json (composite: true, references: [common])

│ └── src/

│ └── server.ts

└── web/

├── tsconfig.json (composite: true, references: [common, api])

└── src/

└── app.tsx</code></pre>

<h3>Compilação Incremental e Build Mode</h3>

<p>A compilação incremental é um game-changer para projetos grandes. O TypeScript armazena informações do build anterior em <code>tsBuildInfoFile</code>, permitindo que recompilações processem apenas arquivos que mudaram. Combinado com Project References, você obtém builds extremamente rápidos.</p>

<pre><code class="language-typescript">// scripts/build.ts - usando a TypeScript Compiler API

import * as ts from &#039;typescript&#039;;

import * as path from &#039;path&#039;;

function buildProject(projectPath: string) {

const configPath = ts.findConfigFile(

projectPath,

ts.sys.fileExists,

&#039;tsconfig.json&#039;

);

if (!configPath) {

throw new Error(tsconfig.json não encontrado em ${projectPath});

}

const config = ts.readConfigFile(configPath, ts.sys.readFile);

const parsedConfig = ts.parseJsonConfigFileContent(

config.config,

ts.sys,

path.dirname(configPath)

);

// Usar o builder para compilação incremental

const host = ts.createIncrementalCompilerHost(parsedConfig.options);

const builder = ts.createIncrementalProgram({

rootNames: parsedConfig.fileNames,

options: parsedConfig.options,

host

});

const result = builder.emit();

const diagnostics = ts.getPreEmitDiagnostics(builder.getProgram());

diagnostics.forEach(diagnostic =&gt; {

if (diagnostic.file) {

const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(

diagnostic.start!

);

console.log(

${diagnostic.file.fileName} (${line + 1},${character + 1}): ${ts.flattenDiagnosticMessageText(diagnostic.messageText, &#039;\n&#039;)}

);

}

});

return { exitCode: result.emitSkipped ? 1 : 0, builder };

}

buildProject(&#039;./packages/common&#039;);</code></pre>

<h3>Estratégias Avançadas: PathMapping e Resoluções Customizadas</h3>

<p>Para projetos complexos, <code>baseUrl</code> e <code>paths</code> do <code>tsconfig.json</code> são essenciais. Eles permitem imports limpos sem caminhos relativos confusos. Combinados com Project References, criam uma estrutura de código profissional e escalável.</p>

<pre><code class="language-json">{

&quot;compilerOptions&quot;: {

&quot;baseUrl&quot;: &quot;.&quot;,

&quot;paths&quot;: {

&quot;@common/&quot;: [&quot;packages/common/src/&quot;],

&quot;@api/&quot;: [&quot;packages/api/src/&quot;],

&quot;@types/&quot;: [&quot;packages/common/src/types/&quot;],

&quot;@utils/&quot;: [&quot;packages/common/src/utils/&quot;]

},

&quot;composite&quot;: true,

&quot;declaration&quot;: true,

&quot;incremental&quot;: true

},

&quot;references&quot;: [

{ &quot;path&quot;: &quot;./packages/common&quot; },

{ &quot;path&quot;: &quot;./packages/api&quot; }

]

}</code></pre>

<p>Com essa configuração, você importa assim:</p>

<pre><code class="language-typescript">// Em packages/api/src/server.ts

import { User } from &#039;@types/models&#039;;

import { formatDate } from &#039;@utils/date&#039;;

import { UserService } from &#039;@api/services/user&#039;;

export class ApiServer {

private userService: UserService;

constructor() {

this.userService = new UserService();

}

async getUser(id: string): Promise&lt;User&gt; {

const user = await this.userService.findById(id);

return {

...user,

createdAt: formatDate(user.createdAt)

};

}

}</code></pre>

<h2>Conclusão</h2>

<p>Dominar <code>tsconfig.json</code> avançado e Project References transforma sua capacidade de trabalhar com código TypeScript em larga escala. Os três pontos principais aprendidos são: <strong>(1)</strong> configurações como <code>incremental</code>, <code>composite</code> e <code>declaration</code> são fundamentais para builds rápidos e modulares; <strong>(2)</strong> Project References permitem que você organize código em múltiplos projetos compilados independentemente, acelerando o desenvolvimento; <strong>(3)</strong> <code>baseUrl</code> e <code>paths</code>, quando bem planejados, criam uma estrutura de imports intuitiva e escalável que melhora significativamente a manutenibilidade do projeto.</p>

<p>Aplique esses conceitos progressivamente: comece com configurações básicas, evoluia para Project References quando seu projeto crescer, e domine path mapping quando sua estrutura exigir múltiplos pacotes interdependentes.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://www.typescriptlang.org/tsconfig" target="_blank" rel="noopener noreferrer">TypeScript Handbook - tsconfig.json Reference</a></li>

<li><a href="https://www.typescriptlang.org/docs/handbook/project-references.html" target="_blank" rel="noopener noreferrer">TypeScript Project References Documentation</a></li>

<li><a href="https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API" target="_blank" rel="noopener noreferrer">TypeScript Compiler API Documentation</a></li>

<li><a href="https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html" target="_blank" rel="noopener noreferrer">Building Large-Scale TypeScript Applications - Microsoft</a></li>

<li><a href="https://www.typescriptlang.org/docs/handbook/project-references.html#handbook-content" target="_blank" rel="noopener noreferrer">Monorepos with TypeScript and Project References</a></li>

</ul>

Comentários

Mais em JavaScript Avançado

Como Usar Testes End-to-End com Playwright: Page Object Model e CI Integration em Produção
Como Usar Testes End-to-End com Playwright: Page Object Model e CI Integration em Produção

O que é Playwright e Por Que Page Object Model? Playwright é um framework de...

Guia Completo de Next.js Avançado: SSR, SSG, ISR e App Router com Server Components
Guia Completo de Next.js Avançado: SSR, SSG, ISR e App Router com Server Components

Renderização no Next.js: Entendendo SSR, SSG e ISR A escolha da estratégia de...

Como Usar Segurança em Node.js: Injeção, SSRF, Path Traversal e Hardening em Produção
Como Usar Segurança em Node.js: Injeção, SSRF, Path Traversal e Hardening em Produção

Injeção em Node.js A injeção é uma das vulnerabilidades mais críticas em apli...