Aparência
Estrutura e Organização de Código
Para abordar a estrutura e organização do código, especialmente quando falamos de melhorar a manutenção e organização em um contexto de um projeto Mirage JS, é crucial entender como uma boa estrutura de diretórios e práticas de codificação podem influenciar diretamente na escalabilidade e manutenibilidade do seu projeto. Vamos desmembrar isso em partes:
1. Melhorando a Manutenção do Código
Manter um código limpo e bem organizado é essencial para que ele seja fácil de entender, modificar e testar. Aqui estão algumas práticas recomendadas:
- Modularidade: Divida o código em módulos ou componentes com responsabilidades claramente definidas. Isso não apenas facilita o entendimento do código, mas também permite reusá-lo.
- Princípio de Responsabilidade Única: Cada módulo ou função deve ter um e único motivo para mudar. Isso ajuda a evitar o acoplamento e facilita os testes.
- Convenções de Codificação: Mantenha um padrão de nomenclatura e estilização. Isso ajuda novos desenvolvedores a se familiarizarem com o código mais rapidamente.
- Documentação: Comente o código quando necessário e mantenha uma documentação atualizada, o que é vital para projetos em equipe.
2. Organizando Arquivos e Pastas no Mirage JS
Mirage JS é uma biblioteca de simulação de API que permite que front-end developers construam, testem e compartilhem uma aplicação completa antes mesmo do back-end estar pronto. A organização de arquivos em um projeto Mirage JS pode seguir a seguinte estrutura, assumindo que você está:
plaintext
/src
/mirage
- @types # Tipos personalizados para Mirage
- index.d.ts
/factories # Fábricas para gerar dados de teste
- index.ts
- utils.ts
- userFactory.ts
- postFactory.ts
/fixtures # Dados fixos iniciais para o desenvolvimento
- index.ts
- users.json
/models # Modelos Mirage representando dados
- index.ts
/routes # Definição de rotas Mirage
- index.ts
/seeds # Dados iniciais para carregar no servidor Mirage
- index.ts
- server.ts # Configuração do servidor Mirage
- @types: Pasta opcional para definir tipos personalizados para Mirage JS.
- factories: Permite a criação de dados de maneira programática para testes e desenvolvimento.
- fixtures: Dados estáticos que podem ser usados para carregar estados iniciais.
- models: Define os modelos de dados que imitam sua API backend.
- routes: Define as rotas Mirage que correspondem às rotas da sua API backend.
- seeds: Dados iniciais que podem ser carregados no servidor Mirage para simular um estado inicial.
- server.ts: Arquivo onde o servidor Mirage é configurado e inicializado.
3. Exemplo Prático: Criacão dos arquivos
Vamos criar um exemplo prático para ilustrar a organização de arquivos e pastas em um projeto Mirage JS. Suponha que você tenha um aplicativo de gerenciamento de usuários e deseja simular uma API backend usando Mirage JS. Aqui está como você pode organizar seus arquivos:
@types/index.d.ts
typescript
// src/mirage/@types/index.d.ts
export type Post = {
id: number;
title: string;
content: string;
userId: number;
};
export type User = {
id: number;
name: string;
email: string;
role: "admin" | "user";
posts: Post[];
};
factories/index.ts
typescript
// src/mirage/factories/index.ts
import userFactory from "./userFactory";
import postFactory from "./postFactory";
/*
* factories are contained in a single object, that's why we
* destructure what's coming from users and the same should
* be done for all future factories
*/
export default {
...userFactory,
...postFactory,
};
factories/utils.ts
typescript
// src/mirage/factories/utils.ts
import { v4 as uuid } from "uuid";
import { faker } from "@faker-js/faker";
export const randomNumber = (quantity: number) =>
Math.floor(Math.random() * quantity) + 1;
export const randomUUID = () => {
return uuid();
};
factories/userFactory.ts
typescript
// src/mirage/factories/userFactory.ts
import type { Server, ModelInstance } from "miragejs";
import type { User } from "../@types";
/*
* Mirage JS guide on Factories: https://miragejs.com/docs/data-layer/factories
*/
import { Factory } from "miragejs";
import { randomNumber } from "./utils";
/*
* Faker Github repository: https://github.com/Marak/Faker.js#readme
*/
import { faker } from "@faker-js/faker";
export default {
user: Factory.extend<
Partial<
User & {
posts: ModelInstance[];
afterCreate: (user: ModelInstance, server: Server) => void;
}
>
>({
name() {
return faker.person.fullName();
},
email() {
return faker.internet.email();
},
role() {
return faker.helpers.arrayElements(["admin", "user"], 1)[0];
},
afterCreate(user: ModelInstance, server: Server) {
const posts = server.createList("post", randomNumber(5));
user.update({ posts });
},
}),
};
factories/postFactory.ts
typescript
// src/mirage/factories/postFactory.ts
/*
* Mirage JS guide on Factories: https://miragejs.com/docs/data-layer/factories
*/
import { Factory } from "miragejs";
/*
* Faker Github repository: https://github.com/Marak/Faker.js#readme
*/
import { faker } from "@faker-js/faker";
export default {
post: Factory.extend({
title() {
return faker.lorem.words(3);
},
content() {
return faker.lorem.paragraphs(3);
},
}),
};
fixtures/index.ts
typescript
// src/mirage/fixtures/index.ts
/*
* Mirage JS guide on Fixtures: https://miragejs.com/docs/data-layer/fixtures
*/
import users from "./users.json";
export default { users };
fixtures/users.json
json
// src/mirage/fixtures/users.json
[
{
"id": 1,
"name": "John Doe",
"email": "john@email.com",
"role": "admin",
"posts": [
{
"id": 1,
"title": "Hello, World!",
"content": "This is a test post.",
"userId": 1
}
]
},
{
"id": 2,
"name": "Jane Doe",
"email": "jane@email.com",
"role": "user",
"posts": []
}
]
models/index.ts
typescript
// src/mirage/models/index.ts
/*
* Mirage JS guide on Models: https://miragejs.com/docs/data-layer/models
*/
import { Model, hasMany } from "miragejs";
/*
* Everytime you create a new resource you have
* to create a new Model and add it here. It is
* true for Factories and for Fixtures.
*
* Mirage JS guide on Relationships: https://miragejs.com/docs/main-concepts/relationships/
*/
export default {
user: Model.extend({
posts: hasMany(),
}),
post: Model,
};
routes/index.ts
typescript
// src/mirage/routes/index.ts
import type { Server } from "miragejs";
import { Response } from "miragejs";
const timing = 0;
/*
* Mirage JS guide on Routes: https://miragejs.com/docs/route-handlers/functions
*/
export default function routes(this: Server) {
/*
* A resource comprises all operations for a CRUD
* operation. .get(), .post(), .put() and delete().
* Mirage JS guide on Resource: https://miragejs.com/docs/route-handlers/shorthands#resource-helper
*/
// CRUD operações para usuários
this.resource("users", {
timing,
});
// CRUD operações para posts
this.resource("posts", {
timing,
});
}
seeds/index.ts
typescript
// src/mirage/seeds/index.ts
/*
* Mirage JS guide on Seeds: https://miragejs.com/docs/data-layer/factories#in-development
*/
import type { Server } from "miragejs";
import { randomNumber } from "../factories/utils";
const postSeeder = (server: Server) => {
server.createList("post", randomNumber(5));
};
export default function seeds(server: Server) {
server.loadFixtures();
postSeeder(server);
}
server.ts
typescript
// src/mirage/server.ts
import { Server } from "miragejs";
import factories from "./factories";
import fixtures from "./fixtures";
import routes from "./routes";
import models from "./models";
import seeds from "./seeds";
const { VITE_APP_API_URL } = import.meta.env;
const config = (environment: string) => {
const config = {
namespace: VITE_APP_API_URL,
environment,
factories,
fixtures,
models,
routes,
seeds,
};
return config;
};
/**
* Cria um servidor MirageJS com base no ambiente fornecido.
* @param {Object} options - Opções para criar o servidor.
* @param {string} options.environment - O ambiente no qual o servidor será criado. O padrão é 'development'.
* @returns {Server} O servidor MirageJS criado.
*/
export function criarServidor({ environment = "development" } = {}) {
return new Server(config(environment));
}
Este processo de refatoração não apenas limpa o código e reduz a duplicidade, mas também melhora significativamente a manutenção ao centralizar a lógica de dados e usando o poder do TypeScript para segurança de tipo.