Modern Front-end Architecture: A Design System Approach

by Square 56 views
Iklan Headers

Hey guys! Ever feel like your front-end projects are a bit of a mess, with styles and components scattered everywhere? It’s a common problem, right? Well, today we're diving deep into how to set up a modern front-end architecture using a Design System, built from scratch. We're talking about making your code super organized, scalable, and a joy to work with. We'll be leveraging awesome tools like TypeScript, SCSS, and the Atomic Design methodology. Get ready to level up your front-end game!

πŸ“– Table des matiΓ¨res

  1. Vue d'ensemble
  2. Installation des dΓ©pendances
  3. Structure des dossiers (Atomic Design)
  4. Scripts de build
  5. Configuration des outils
  6. Scripts package.json
  7. MΓ©thodologie Atomic Design
  8. Commandes de dΓ©marrage
  9. Configuration Git
  10. Points d'attention

🎯 Vue d'ensemble

Alright, let's get a grip on what we're building here. We're setting up a modern front-end architecture that’s all about creating a cohesive and maintainable Design System. Think of it as the backbone for all your UI elements. We're going to use some powerful tech to make this happen:

  • TypeScript: For robust, type-safe JavaScript. It catches errors early, which is a lifesaver, especially in larger projects. We're compiling it super fast with esbuild.
  • SCSS: Because managing CSS can get wild. SCSS gives us variables, mixins, nesting, and more, making our stylesheets way more organized. We'll be compiling it with Sass.
  • Watch mode: Nobody likes manually re-running builds. Chokidar will keep an eye on our files and automatically recompile everything when we make changes. Super handy for development!
  • Linting & Formatting: ESLint, Stylelint, and Prettier are our code quality guardians. They enforce consistent coding styles and catch potential issues before they become problems.
  • Git hooks: We’re using Husky to automate tasks before we commit, like running linters and formatters. This ensures only clean code gets into our repository.
  • Icons: We’ll even touch on generating an icon font using Python, which is a neat way to manage and scale your icons.

This setup ensures we have a production-ready build process that’s also a dream for developer experience. We’re aiming for optimal performance, maintainability, and a consistent look and feel across your entire application. By setting up this front-end architecture, you're laying the groundwork for future development to be much smoother and faster. It’s all about building smart from the start!


πŸ“¦ Installation des dΓ©pendances

Now, let's get our hands dirty with the actual setup. This part involves installing the necessary tools to power our front-end architecture. We'll split these into two categories: development dependencies and optional production dependencies.

DΓ©pendances de dΓ©veloppement

These are the tools we need to build, lint, and manage our code. Run this command in your project's root directory:

npm install --save-dev \
  @types/node@^24.1.0 \
  chokidar@^4.0.3 \
  concurrently@^9.2.0 \
  esbuild@^0.25.8 \
  eslint@^8.0.0 \
  husky@^8.0.3 \
  prettier@^3.0.0 \
  sass@^1.89.2 \
  stylelint@^15.0.0 \
  stylelint-config-standard-scss@^10.0.0 \
  typescript@^5.8.3

Let's break down what these are for:

  • @types/node: Provides TypeScript type definitions for Node.js, essential for our build scripts.
  • chokidar: A fantastic library for watching file changes, powering our development watch mode.
  • concurrently: Allows us to run multiple npm scripts simultaneously, like running both TS and SCSS watchers at once.
  • esbuild: A super-fast bundler and minifier for JavaScript and TypeScript. It's our go-to for compiling our TS code.
  • eslint: The standard linter for JavaScript. It helps maintain code quality and consistency.
  • husky: A tool for managing Git hooks. We'll use it to run checks before commits.
  • prettier: An opinionated code formatter that ensures a consistent style across the codebase.
  • sass: The actual preprocessor for compiling our SCSS files into CSS.
  • stylelint: A powerful linter specifically for CSS and SCSS, ensuring our styles are clean and error-free.
  • stylelint-config-standard-scss: A popular configuration preset for Stylelint that follows common SCSS best practices.
  • typescript: The superset of JavaScript that brings static typing to our front-end code.

DΓ©pendances de production (optionnelles)

For a design system built from scratch, you might not need many production dependencies initially. However, here are a couple of common ones you might consider:

# npm install normalize.css  # Pour un reset CSS
  • normalize.css: This is a great tool to apply a consistent baseline of styles across different browsers, reducing cross-browser inconsistencies. It's a good practice to include a CSS reset or normalization.

With these dependencies installed, you've got all the building blocks for your advanced front-end architecture and a solid design system foundation. Ready to organize that structure?


πŸ—οΈ Structure des dossiers (Atomic Design)

Okay, so you’ve got your tools installed. Now, let’s talk about how we’re going to organize everything. A well-structured project is key to a maintainable front-end architecture, and we're going to use the Atomic Design methodology for this. This approach breaks down UIs into smaller, reusable components, making everything much easier to manage and scale. Imagine building with LEGOs – that’s the vibe!

Here’s the directory structure we’ll be aiming for, nested within your main project folder (let's assume it's symfony-project/ for this example):

symfony-project/
β”œβ”€β”€ package.json
β”œβ”€β”€ tsconfig.json
β”œβ”€β”€ .eslintrc.js
β”œβ”€β”€ .prettierrc
β”œβ”€β”€ .stylelintrc.js
β”œβ”€β”€ scripts/
β”‚   β”œβ”€β”€ build-ts.js
β”‚   β”œβ”€β”€ build-scss.js
β”‚   β”œβ”€β”€ build-scss-modern.js
β”‚   β”œβ”€β”€ watch-ts.js
β”‚   β”œβ”€β”€ watch-scss.js
β”‚   └── compile-dev.js
β”œβ”€β”€ public/
β”‚   β”œβ”€β”€ ts/
β”‚   β”‚   β”œβ”€β”€ main.ts
β”‚   β”‚   β”œβ”€β”€ atoms/
β”‚   β”‚   β”‚   β”œβ”€β”€ button.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ input.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ badge.ts
β”‚   β”‚   β”‚   └── icon.ts
β”‚   β”‚   β”œβ”€β”€ molecules/
β”‚   β”‚   β”‚   β”œβ”€β”€ form-group.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ search-box.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ chip.ts
β”‚   β”‚   β”‚   └── tooltip.ts
β”‚   β”‚   β”œβ”€β”€ organisms/
β”‚   β”‚   β”‚   β”œβ”€β”€ modal.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ navbar.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ form-wizard.ts
β”‚   β”‚   β”‚   └── data-table.ts
β”‚   β”‚   β”œβ”€β”€ templates/
β”‚   β”‚   β”‚   β”œβ”€β”€ page-layout.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ dashboard-layout.ts
β”‚   β”‚   β”‚   └── auth-layout.ts
β”‚   β”‚   └── utils/
β”‚   β”‚       β”œβ”€β”€ dom.ts
β”‚   β”‚       β”œβ”€β”€ events.ts
β”‚   β”‚       └── validators.ts
β”‚   β”œβ”€β”€ scss/
β”‚   β”‚   β”œβ”€β”€ main.scss
β”‚   β”‚   β”œβ”€β”€ abstracts/
β”‚   β”‚   β”‚   β”œβ”€β”€ _index.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _variables.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _functions.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _mixins.scss
β”‚   β”‚   β”‚   └── tokens/
β”‚   β”‚   β”‚       β”œβ”€β”€ _colors.scss
β”‚   β”‚   β”‚       β”œβ”€β”€ _typography.scss
β”‚   β”‚   β”‚       β”œβ”€β”€ _spacing.scss
β”‚   β”‚   β”‚       β”œβ”€β”€ _breakpoints.scss
β”‚   β”‚   β”‚       β”œβ”€β”€ _elevation.scss
β”‚   β”‚   β”‚       β”œβ”€β”€ _border-radius.scss
β”‚   β”‚   β”‚       └── _transitions.scss
β”‚   β”‚   β”œβ”€β”€ vendor/
β”‚   β”‚   β”‚   β”œβ”€β”€ _normalize.scss
β”‚   β”‚   β”‚   └── _vendor-overrides.scss
β”‚   β”‚   β”œβ”€β”€ base/
β”‚   β”‚   β”‚   β”œβ”€β”€ _reset.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _normalize.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _typography.scss
β”‚   β”‚   β”‚   └── _global.scss
β”‚   β”‚   β”œβ”€β”€ utilities/
β”‚   β”‚   β”‚   β”œβ”€β”€ _spacing.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _colors.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _layout.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _typography.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _responsive.scss
β”‚   β”‚   β”‚   └── _accessibility.scss
β”‚   β”‚   β”œβ”€β”€ atoms/
β”‚   β”‚   β”‚   β”œβ”€β”€ _button.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _input.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _label.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _textarea.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _select.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _checkbox-radio.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _icon.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _badge.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _alert.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _spinner.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _helper.scss
β”‚   β”‚   β”‚   └── _feedback.scss
β”‚   β”‚   β”œβ”€β”€ molecules/
β”‚   β”‚   β”‚   β”œβ”€β”€ _form-group.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _search-box.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _chip.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _tooltip.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _toast.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _notification-badge.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _switch.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _date-picker.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _file-upload.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _select-multiple.scss
β”‚   β”‚   β”‚   └── _selectable-card.scss
β”‚   β”‚   β”œβ”€β”€ organisms/
β”‚   β”‚   β”‚   β”œβ”€β”€ _modal.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _dialog.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _navbar.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _form-wizard.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _data-table.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _step-container.scss
β”‚   β”‚   β”‚   └── _multi-step-form.scss
β”‚   β”‚   β”œβ”€β”€ templates/
β”‚   β”‚   β”‚   β”œβ”€β”€ _layout-dashboard.scss
β”‚   β”‚   β”‚   β”œβ”€β”€ _layout-auth.scss
β”‚   β”‚   β”‚   └── _layout-public.scss
β”‚   β”‚   └── pages/
β”‚   β”‚       β”œβ”€β”€ _home.scss
β”‚   β”‚       β”œβ”€β”€ _dashboard.scss
β”‚   β”‚       └── _errors.scss
β”‚   └── dist/
β”‚       β”œβ”€β”€ latest/           ← Latest build (for cache busting)
β”‚       β”‚   β”œβ”€β”€ css/
β”‚       β”‚   β”‚   └── main.min.css
β”‚       β”‚   └── js/
β”‚       β”‚       └── main.min.js
β”‚       └── v.1.0.0/             ← Version from package.json
β”‚           β”œβ”€β”€ css/
β”‚           β”‚   └── main.min.css
β”‚           └── js/
β”‚               └── main.min.js

This structure is the heart of our Atomic Design implementation. It separates concerns beautifully, making your front-end architecture super organized. Let’s break down the Atomic Design part a bit more.


🧬 Méthodologie Atomic Design

Atomic Design, coined by Brad Frost, is a brilliant way to build user interfaces systematically. It breaks down interfaces into five distinct levels, much like chemistry breaks down matter.

  1. πŸ”¬ Atoms: These are the most basic building blocks. Think of HTML tags like labels, inputs, buttons, or even abstract elements like colors, fonts, and animations (our design tokens). They can't be broken down further without losing their meaning. In our scss/atoms/ and public/ts/atoms/ folders, you'll find things like buttons, inputs, and badges.
  2. πŸ§ͺ Molecules: When atoms are combined to form a simple, reusable functional unit, they become molecules. For example, a label and an input field might combine to form a form field molecule. Our scss/molecules/ and public/ts/molecules/ folders will hold these, like a form-group or a search-box.
  3. 🦠 Organisms: These are more complex UI components composed of molecules and/or atoms. An organism might be a header section of a page, containing a logo (atom), navigation (molecule), and a search bar (molecule). Check out scss/organisms/ and public/ts/organisms/ for things like modal or navbar.
  4. πŸ“ Templates: At this level, we're looking at page-level structures. Templates are essentially wireframes that arrange organisms into a layout. They focus on the underlying content structure without the actual content. Think of dashboard-layout or auth-layout in scss/templates/ and public/ts/templates/.
  5. πŸ“„ Pages: This is the highest level of fidelity. Pages are specific instances of templates where placeholder content is replaced with real representative content. This shows the final UI as users will see it. Our scss/pages/ folder might have styles for _home.scss or _dashboard.scss.

By following this hierarchy, we create a scalable and maintainable front-end architecture. It ensures consistency and makes it super easy to update or replace components without breaking the entire system. This methodical approach is what makes a design system so powerful!


� Système de Versioning

The build process for our front-end architecture needs to be smart, especially when it comes to managing assets like CSS and JavaScript. We want to leverage browser caching effectively while also ensuring that users always get the latest updates. That’s where our clever versioning strategy comes in. When our build scripts run, they’ll generate two sets of compiled files for both CSS and JavaScript.

πŸ”„ Structure de versioning

Here’s how the output directory public/dist/ will be structured:

  • latest/: This directory will always contain the most recently compiled version of your assets. Files here will have unique cache-busting filenames or be placed in a directory that changes frequently. This is ideal for linking in your HTML because browsers will be forced to re-download them whenever they change, ensuring users always have the latest styles and scripts.
  • v.{version}/: This directory will contain a specific version of your compiled assets, corresponding to the version number defined in your package.json. For example, if your package.json has "version": "1.0.0", you’ll see a v.1.0.0/ folder. This is perfect for long-term caching. Since the path changes with every version update, you can set very aggressive caching rules for these files on your CDN or server.

🎯 Utilisation

When you link these assets in your HTML, you'll use them like this:

<!-- Version latest (ideal for cache busting) -->
<link rel="stylesheet" href="/dist/latest/css/main.min.css" />
<script type="module" src="/dist/latest/js/main.min.js"></script>

<!-- Version spΓ©cifique (ideal for long-term caching) -->
<link rel="stylesheet" href="/dist/v.1.0.0/css/main.min.css" />
<script type="module" src="/dist/v.1.0.0/js/main.min.js"></script>

⚑ Avantages

This dual-directory approach offers several significant benefits for your front-end architecture:

  • Cache busting: By linking to latest/, you ensure that users automatically fetch the newest versions of your assets whenever they change, preventing issues with stale cached files.
  • Versionning: Having specific versioned folders (v.1.0.0/) allows you to roll back to previous versions if needed and provides a stable URL for long-term caching.
  • CDN friendly: Long-term caching for versioned assets is a major performance win. You can instruct CDNs and browsers to cache these files for extended periods, reducing load times significantly.

This sophisticated versioning system is a cornerstone of a robust design system build process, ensuring both performance and reliability.


οΏ½πŸ› οΈ Scripts de build

This is where the magic happens, guys! We're going to define scripts that automate the compilation and optimization of our TypeScript and SCSS code. These scripts are the engine behind our modern front-end architecture, ensuring we have efficient builds for both development and production. We've got a suite of scripts to handle different needs:

🎯 A. scripts/build-ts.js - Build Production TypeScript avec Versioning

This script compiles our TypeScript code into optimized, minified JavaScript bundles suitable for production. Crucially, it adheres to our versioning strategy.

const esbuild = require('esbuild');
const path = require('path');
const fs = require('fs');

async function buildTypeScript() {
  try {
    // Lire la version depuis package.json
    const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
    const version = packageJson.version;

    console.log(`πŸ—οΈ Building TypeScript v${version}...`);

    // Build principal avec minification
    const result = await esbuild.build({
      entryPoints: ['public/ts/main.ts'],
      bundle: true,
      format: 'esm',
      target: ['es2020'],
      platform: 'browser',
      minify: true, // Toujours minifiΓ©
      sourcemap: false, // Pas de sourcemap pour les fichiers finaux
      treeShaking: true, // Optimisation pour production
      write: false, // Ne pas Γ©crire automatiquement
      outExtension: { '.js': '.min.js' },
    });

    // CrΓ©er les dossiers de destination
    const latestDir = 'public/dist/latest/js';
    const versionDir = `public/dist/v.${version}/js`;
    
    if (!fs.existsSync(latestDir)) {
      fs.mkdirSync(latestDir, { recursive: true });
    }
    if (!fs.existsSync(versionDir)) {
      fs.mkdirSync(versionDir, { recursive: true });
    }

    // Γ‰crire les fichiers minifiΓ©s dans les deux dossiers
    for (const file of result.outputFiles) {
      const fileName = path.basename(file.path, '.js') + '.min.js';
      
      const latestPath = path.join(latestDir, fileName);
      const versionPath = path.join(versionDir, fileName);
      
      fs.writeFileSync(latestPath, file.text);
      fs.writeFileSync(versionPath, file.text);
      
      console.log(`βœ… Generated: ${latestPath}`);
      console.log(`βœ… Generated: ${versionPath}`);
    }    console.log(`βœ… TypeScript build completed (v${version})`);
  } catch (error) {
    console.error('❌ TypeScript build failed:', error);
    process.exit(1);
  }
}

buildTypeScript();

This script uses esbuild for blazing-fast compilation. It bundles our entry point (main.ts), minifies the output, and crucially, writes the resulting .min.js files into both the public/dist/latest/js/ and public/dist/v.{version}/js/ directories, fulfilling our versioning strategy. It also reads the current version from package.json to create the correct versioned path.

🎨 B. scripts/build-scss.js - Build Production SCSS avec Versioning

Similarly, this script compiles our SCSS into minified CSS, ready for production, and also handles the versioning.

const sass = require('sass');
const fs = require('fs');
const path = require('path');

function buildSCSS() {
  try {
    // Lire la version depuis package.json
    const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
    const version = packageJson.version;

    console.log(`🎨 Building SCSS v${version}...`);

    // Compilation avec minification (compressed)
    const result = sass.compile('public/scss/main.scss', {
      style: 'compressed', // Toujours minifiΓ©
      sourceMap: false, // Pas de sourcemap pour les fichiers finaux
    });

    // CrΓ©er les dossiers de destination
    const latestDir = 'public/dist/latest/css';
    const versionDir = `public/dist/v.${version}/css`;

    if (!fs.existsSync(latestDir)) {
      fs.mkdirSync(latestDir, { recursive: true });
    }
    if (!fs.existsSync(versionDir)) {
      fs.mkdirSync(versionDir, { recursive: true });
    }

    // Γ‰crire les fichiers CSS minifiΓ©s dans les deux dossiers
    const latestPath = `${latestDir}/main.min.css`;
    const versionPath = `${versionDir}/main.min.css`;

    fs.writeFileSync(latestPath, result.css);
    fs.writeFileSync(versionPath, result.css);

    console.log(`βœ… Generated: ${latestPath}`);
    console.log(`βœ… Generated: ${versionPath}`);
    console.log(`βœ… SCSS build completed (v${version})`);
  } catch (error) {
    console.error('❌ SCSS build failed:', error);
    process.exit(1);
  }
}

buildSCSS();

This script uses the sass compiler to turn our main.scss file into compressed CSS. Like the TypeScript build, it places the output (main.min.css) into both the latest/ and versioned directories, ensuring our design system assets are always up-to-date and properly versioned.

πŸ‘€ C. scripts/watch-ts.js - Watch Mode TypeScript avec Versioning

For development, we want instant feedback. This script uses chokidar to watch our TypeScript files. When any change is detected, it automatically triggers the production build script (build-ts.js) to recompile everything.

const chokidar = require('chokidar');
const { execSync } = require('child_process');

console.log('πŸ” Watching TypeScript files...');
console.log('πŸ“ Generating versioned .min.js files on change...');
console.log(
  'πŸ’‘ Files will be generated in both latest/ and v{version}/ folders'
);

chokidar
  .watch('public/ts/**/*.ts', {
    ignored: /node_modules/,
    persistent: true,
  })
  .on('change', (path) => {
    console.log(`πŸ“ TypeScript file changed: ${path}`);
    try {
      execSync('node scripts/build-ts.js', { stdio: 'inherit' });
    } catch (error) {
      console.error('❌ Build failed');
    }
  });

This is a game-changer for productivity. Instead of manually running npm run build every time you save a file, this script does it for you in the background. It ensures our front-end architecture development is fast and fluid.

πŸ‘€ D. scripts/watch-scss.js - Watch Mode SCSS avec Versioning

This companion script does the same for our SCSS files. It watches public/scss/**/*.scss and triggers build-scss.js whenever a change occurs.

const chokidar = require('chokidar');
const { execSync } = require('child_process');

console.log('πŸ” Watching SCSS files...');
console.log('🎨 Generating versioned .min.css files on change...');
console.log(
  'πŸ’‘ Files will be generated in both latest/ and v{version}/ folders'
);

chokidar
  .watch('public/scss/**/*.scss', {
    ignored: /node_modules/,
    persistent: true,
  })
  .on('change', (path) => {
    console.log(`🎨 SCSS file changed: ${path}`);
    try {
      execSync('node scripts/build-scss.js', { stdio: 'inherit' });
    } catch (error) {
      console.error('❌ SCSS build failed');
    }
  });

Running npm run dev will execute both watch-ts.js and watch-scss.js concurrently, giving you a seamless development experience where your code is always compiled and ready.

πŸ”§ E. scripts/compile-ts.js - DΓ©veloppement TypeScript (non minifiΓ©)

During development, we often prefer readable code with source maps for easier debugging. This script uses esbuild to compile TypeScript without minification and with source maps enabled.

const esbuild = require('esbuild');
const path = require('path');
const fs = require('fs');

async function compileTypeScript() {
  try {
    // Build de dΓ©veloppement (non minifiΓ©, config similaire Γ  watch-ts.js)
    const result = await esbuild.build({
      entryPoints: ['public/ts/main.ts'],
      bundle: true,
      format: 'esm',
      target: ['es2020'],
      platform: 'browser',
      minify: false, // Pas de minification
      sourcemap: true, // Sourcemap pour debug
      treeShaking: false, // Pas d'optimisation pour le debug
      write: false,
      outExtension: { '.js': '.js' }, // Extension normale
    });

    // CrΓ©er le dossier de destination s'il n'existe pas
    if (!fs.existsSync('public/dist/js')) {
      fs.mkdirSync('public/dist/js', { recursive: true });
    }

    // Γ‰crire le fichier non minifiΓ©
    for (const file of result.outputFiles) {
      const fileName = path.basename(file.path);
      const outputPath = path.join('public/dist/js', fileName);
      fs.writeFileSync(outputPath, file.text);
      console.log(`βœ… Generated: ${outputPath}`);
    }

    console.log(
      'βœ… TypeScript compilation completed (non-minified with sourcemap)'
    );
  } catch (error) {
    console.error('❌ TypeScript compilation failed:', error);
    process.exit(1);
  }
}

compileTypeScript();

This script outputs to public/dist/js/ and generates source maps, making debugging much simpler when you’re deep in development.

πŸ”§ F. scripts/compile-scss.js - DΓ©veloppement SCSS (non minifiΓ©)

This script compiles SCSS to expanded CSS with source maps for debugging purposes during development.

const sass = require('sass');
const fs = require('fs');
const path = require('path');

function compileSCSS() {
  try {
    // Compilation de dΓ©veloppement (non minifiΓ©e)
    const result = sass.compile('public/scss/main.scss', {
      style: 'expanded', // Format lisible
      sourceMap: true, // Sourcemap pour debug
    });

    // CrΓ©er le dossier de destination s'il n'existe pas
    if (!fs.existsSync('public/dist/css')) {
      fs.mkdirSync('public/dist/css', { recursive: true });
    }

    // Γ‰crire le fichier CSS non minifiΓ©
    const outputPath = 'public/dist/css/main.css';
    fs.writeFileSync(outputPath, result.css);

    // Γ‰crire la sourcemap si disponible
    if (result.sourceMap) {
      const sourcemapPath = 'public/dist/css/main.css.map';
      fs.writeFileSync(sourcemapPath, JSON.stringify(result.sourceMap));
      console.log(`βœ… Generated: ${sourcemapPath}`);
    }

    console.log(`βœ… Generated: ${outputPath}`);
    console.log('βœ… SCSS compilation completed (non-minified with sourcemap)');
  } catch (error) {
    console.error('❌ SCSS compilation failed:', error);
    process.exit(1);
  }
}

compileSCSS();

Similar to the TS compilation script, this outputs unminified CSS and its corresponding source map to public/dist/css/.

🎨 G. scripts/generate_icon_font.py - Générateur d'icon font

Managing icons can be a pain. This Python script is a placeholder for generating an icon font from SVG files. You'd typically use libraries or services like Fontello or IcoMoon for a full implementation, but this shows where that process would fit into your front-end architecture.

#!/usr/bin/env python3
"""
Script de gΓ©nΓ©ration d'icon font
Requis: fonttools, lxml
Installation: pip install fonttools lxml
"""

import os
import sys
from pathlib import Path

def generate_icon_font():
    """Génère un icon font à partir de fichiers SVG"""
    icons_dir = Path("public/icons")
    output_dir = Path("public/font")

    if not icons_dir.exists():
        print("❌ Dossier public/icons non trouvé")
        return False

    # CrΓ©er le dossier de sortie
    output_dir.mkdir(parents=True, exist_ok=True)

    # Ici, implΓ©menter la logique de gΓ©nΓ©ration d'icon font
    # ou utiliser un outil comme fontello, icomoon, etc.

    print("βœ… Icon font generated")
    return True

if __name__ == "__main__":
    generate_icon_font()

This script provides a hook for integrating icon font generation, a common requirement for comprehensive design systems.

These build scripts form the core of our automated front-end workflow, ensuring our design system is efficiently compiled, versioned, and ready for use.


βš™οΈ Configuration des outils

To make our build scripts and the overall front-end architecture work smoothly, we need to configure the linters and compilers we've installed. These configuration files tell tools like TypeScript, ESLint, Stylelint, and Prettier how we want our code to behave and look. Getting these right is crucial for maintaining consistency and quality across your design system.

πŸ“ A. tsconfig.json - Configuration TypeScript

This file configures the TypeScript compiler. It defines compilation options, module resolution strategies, and which files to include or exclude.

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "node",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "outDir": "./dist/js",
    "rootDir": "./public/ts",
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  },
  "include": ["public/ts/**/*"],
  "exclude": ["node_modules", "dist"]
}
  • target: Specifies the ECMAScript target version. ES2020 is a good modern baseline.
  • module: Sets the module system. ESNext is flexible and works well with modern bundlers.
  • moduleResolution: How modules are resolved. node is standard.
  • strict: Enables all strict type-checking options. Highly recommended!
  • esModuleInterop: Allows default imports from CommonJS modules.
  • skipLibCheck: Skips type checking of declaration files, speeding up compilation.
  • forceConsistentCasingInFileNames: Prevents issues with case sensitivity in filenames.
  • outDir & rootDir: Define where compiled JS files go and where the TS source files are located.
  • declaration, declarationMap, sourceMap: Generate type definition files and source maps, useful for debugging and for consumers of your library.

πŸ” B. .eslintrc.js - Configuration ESLint

This configures ESLint to enforce JavaScript/TypeScript code style and catch potential errors. We're using a basic setup here, but you'd typically extend this with more specific rules or plugins.

module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: ['eslint:recommended'],
  parserOptions: {
    ecmaVersion: 12,
    sourceType: 'module',
  },
  rules: {
    indent: ['error', 2],
    quotes: ['error', 'single'],
    semi: ['error', 'always'],
  },
};
  • env: Defines the environments your code will run in (browser, Node.js).
  • extends: Specifies the base configuration to inherit from. eslint:recommended provides a good set of default rules.
  • rules: Allows you to override or add specific rules. Here, we enforce 2-space indentation, single quotes, and semicolons.

🎨 C. .stylelintrc.json - Configuration Stylelint

Stylelint helps maintain clean and consistent CSS/SCSS. This configuration uses a standard SCSS preset and adds a couple of custom rules.

{
  "extends": ["stylelint-config-standard-scss"],
  "rules": {
    "indentation": 2,
    "string-quotes": "single"
  }
}
  • extends: We're extending stylelint-config-standard-scss, which provides a solid set of rules for SCSS.
  • rules: Similar to ESLint, we can customize rules. Here, we enforce 2-space indentation and single quotes for strings.

✨ D. .prettierrc - Configuration Prettier

Prettier automatically formats your code. This configuration sets our preferred formatting style.

{
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5"
}
  • semi: Adds semicolons at the end of statements.
  • singleQuote: Uses single quotes for strings.
  • tabWidth: Sets the indentation width to 2 spaces.
  • trailingComma: Adds trailing commas where valid (e.g., in object literals, arrays).

Configuring these tools properly is essential for a smooth development workflow and a high-quality design system. It ensures your front-end architecture is not only functional but also beautiful and consistent!


πŸ“¦ Scripts package.json

Your package.json file is the central hub for managing your project's scripts. It’s where we define commands to build, compile, watch, lint, and format our code. These scripts automate the tasks needed for our front-end architecture and design system, making development and deployment much more efficient.

Here are the key scripts we'll add to the "scripts" section of your package.json:

{
  "scripts": {
    "build": "concurrently \"npm:build:*\"",
    "build:ts": "node scripts/build-ts.js",
    "build:scss": "node scripts/build-scss.js",
    "compile": "concurrently \"npm:compile:*\"",
    "compile:ts": "node scripts/compile-ts.js",
    "compile:scss": "node scripts/compile-scss.js",
    "generate-icon-font": "./scripts/generate_icon_font.py",
    "dev": "concurrently \"npm:dev:*\"",
    "dev:ts": "node scripts/watch-ts.js",
    "dev:scss": "node scripts/watch-scss.js",
    "lint": "stylelint 'public/**/*.scss' && eslint 'public/**/*.js'",
    "lint:fix": "stylelint 'public/**/*.scss' --fix && eslint 'public/**/*.js' --fix",
    "format": "prettier --write 'public/**/*.{js,ts,scss}'",
    "precommit": "npm run lint && npm run format",
    "prepare": "husky install"
  }
}

Let's break down what each of these commands does:

Script Description Usage
npm run build πŸš€ Production (minifiΓ©) Fichiers optimisΓ©s .min.js + .min.css
npm run compile πŸ”§ DΓ©veloppement Fichiers lisibles avec sourcemaps
npm run dev πŸ‘€ Watch mode Auto-rebuild en temps rΓ©el
npm run lint πŸ” Analyse qualitΓ© ESLint + Stylelint
npm run lint:fix πŸ”§ Correction automatique ESLint + Stylelint avec auto-fix
  • build: This is our main production build script. It uses concurrently to run build:ts and build:scss in parallel, creating optimized, minified assets in the dist/ folder with versioning.
  • build:ts & build:scss: These are the individual scripts that execute our TypeScript and SCSS production compilation logic defined in the scripts/ directory.
  • compile: This command is for development. It runs compile:ts and compile:scss in parallel, generating readable, unminified files with source maps for easier debugging.
  • compile:ts & compile:scss: These scripts execute the development compilation logic.
  • generate-icon-font: Runs our Python script to generate icon fonts.
  • dev: This is your go-to command during active development. It runs dev:ts and dev:scss concurrently, which start the watch processes. Any changes you make to your TS or SCSS files will automatically trigger a re-compilation.
  • dev:ts & dev:scss: These scripts start the file watchers for TypeScript and SCSS, respectively.
  • lint: Runs both Stylelint on SCSS and ESLint on JavaScript/TypeScript files to check for code quality issues.
  • lint:fix: Attempts to automatically fix linting issues found by Stylelint and ESLint.
  • format: Uses Prettier to automatically format all your JS, TS, and SCSS files according to the .prettierrc configuration.
  • precommit: This script is designed to run automatically before each Git commit (thanks to Husky). It ensures you lint and format your code before committing, maintaining code quality.
  • prepare: This script is automatically run by npm/yarn after installation. It sets up Husky, our Git hooks manager.

These scripts are essential for a smooth and efficient workflow. They automate repetitive tasks, enforce code quality, and ensure your front-end architecture is always in a good state. Using concurrently for parallel execution speeds things up significantly, especially during development!


πŸ”§ Configuration Git

Version control is fundamental to any software project, and integrating Git hooks can significantly improve code quality and consistency. We're using Husky to manage these hooks, ensuring that certain checks are performed automatically before we commit our code. This is a crucial part of maintaining a robust front-end architecture and a clean design system.

Git Hooks avec Husky

Husky makes it super easy to set up Git hooks. If you followed the dependency installation step, you should already have Husky installed. Now, let's configure it to run our pre-commit checks.

First, you need to install Husky if you haven't already. This command initializes Husky in your project:

# Installer husky
npx husky install

This command creates a .husky/ directory in your project root, which is where Git hooks are stored. It also adds necessary configurations to your package.json.

Next, we'll create a pre-commit hook. This hook will run before Git allows a commit to be made. We want this hook to automatically run our linting and formatting scripts to ensure code quality.

# CrΓ©er le hook pre-commit
npx husky add .husky/pre-commit "npm run precommit"

What does this do?

  1. npx husky add .husky/pre-commit: This command tells Husky to create or update the pre-commit file inside the .husky/ directory.
  2. "npm run precommit": This is the command that will be executed when the pre-commit hook is triggered. We've defined a precommit script in our package.json that runs npm run lint && npm run format. This means that every time you try to commit, your code will first be linted and formatted. If either of these steps fails (e.g., linting errors are found that cannot be auto-fixed), the commit will be aborted, preventing low-quality code from entering your repository.

This setup is incredibly valuable because it:

  • Automates Quality Checks: Developers don't have to remember to run linters or formatters manually; it happens automatically.
  • Ensures Consistency: All code committed adheres to the defined style guides.
  • Reduces Review Time: Code reviews become more efficient as stylistic issues are already resolved.

By integrating Git hooks with Husky, you're building a more disciplined and professional front-end development process. It's a small step that has a big impact on the overall health and maintainability of your design system and front-end architecture.


πŸ“‹ MΓ©thodologie Atomic Design

We've touched on Atomic Design when discussing the folder structure, but let's really dive into how it guides the composition and naming conventions within our front-end architecture. This methodology is the backbone of our Design System, ensuring consistency, reusability, and maintainability. It’s all about building from the smallest units up to the complete interface.

🎯 Règles de composition

This table outlines the dependencies between the different levels of Atomic Design. It's crucial to understand these relationships for building a modular and scalable system:

Niveau Dépendances Règles
πŸ”¬ Atoms Aucune Styles completely autonomous
πŸ§ͺ Molecules Atoms uniquement One clear responsibility
🦠 Organisms Atoms + Molecules Autonomous interface sections
πŸ“ Templates Organisms + structure Positioning without content
πŸ“„ Pages Templates + content Specific instances

Key Takeaways from Composition Rules:

  • Atoms are the fundamental building blocks. They have no dependencies on other UI components. Think of them as indivisible elements with their own styling.
  • Molecules are composed solely of atoms. They represent simple, reusable components with a single, well-defined purpose. This ensures that if you need to change an atom, the impact is contained within the molecules that use it.
  • Organisms can be composed of both atoms and molecules. They form more complex sections of an interface, like a navigation bar or a product card. This level starts to build out distinct parts of the UI.
  • Templates define the layout structure, arranging organisms. They are essentially page skeletons, focusing on the arrangement of components rather than the final content. This separation is key for designing reusable layouts.
  • Pages are the most concrete level, representing specific instances of templates filled with real content. This is where you see the final product, but the underlying structure is built from the lower levels.

This strict composition hierarchy is fundamental to creating a predictable and manageable front-end architecture. It allows us to build complex interfaces by assembling simpler, well-defined parts.

πŸ“› Conventions de nommage

Consistent naming is vital for understanding and navigating a codebase, especially in a large design system. Our naming conventions follow the Atomic Design levels, making it intuitive to identify the scope and purpose of each component.

Niveau Convention Exemples
Atoms Nom simple .btn, .input, .badge
Molecules Fonction descriptive .form-group, .search-box, .user-card
Organisms Section complexe .site-header, .product-grid, .checkout-form
Templates Layout + usage .dashboard-layout, .auth-layout
Pages Contexte spΓ©cifique .home-page, .product-detail

Why these conventions matter:

  • Clarity: A simple name like .btn immediately tells you it’s a button atom. A descriptive name like .form-group clearly indicates a molecule grouping form elements.
  • Scalability: As your design system grows, these conventions prevent naming collisions and make it easier to find and use components.
  • Maintainability: New team members can quickly understand the structure and purpose of different UI parts just by looking at their names.

πŸ—‚οΈ Organisation des fichiers

Within the scss/ and public/ts/ directories, we follow a specific organizational pattern for our components:

  • Un composant = un fichier: Each component (whether atom, molecule, or organism) gets its own file, typically named like _component-name.scss for SCSS partials or component-name.ts for TypeScript.
  • Import ordonnΓ©: In our main SCSS file (main.scss), imports follow a strict order: abstracts (variables, mixins, tokens) β†’ base (resets, globals) β†’ utilities (helper classes) β†’ atoms β†’ molecules β†’ organisms β†’ templates β†’ pages. This order ensures that styles cascade correctly and dependencies are met.
  • Documentation inline: For complex components, we add inline comments explaining their purpose, usage, and any specific considerations.
  • CSS custom properties (variables): We heavily utilize CSS custom properties, especially within our abstracts/tokens/ directory, for theming. This makes dynamic theming (like dark mode) much easier to implement.

Adhering to the Atomic Design methodology provides a solid framework for building a robust and scalable front-end architecture. It ensures that our Design System is not just a collection of styles and components, but a well-thought-out system that promotes consistency and efficiency.


πŸ“„ Fichiers TypeScript d'exemple

Let's look at some practical examples of how our TypeScript files would be structured within our front-end architecture, following the Atomic Design principles. These examples demonstrate how to create reusable components and utility functions that form the basis of our Design System.

public/ts/main.ts - Point d'entrΓ©e principal

This is the main entry point for our TypeScript code. It initializes the design system and exports core utilities and components. When your application loads, this is the first piece of our JavaScript logic that gets executed.

// Design System - Main TypeScript (From Scratch)
console.log('🎨 Design System initialized');

// Core utilities
export * from './utils/dom';
export * from './utils/events';

// Components
export * from './components/modal';
export * from './components/dropdown';
export * from './components/toast';

// Types
export interface ComponentOptions {
  element: HTMLElement;
  options?: Record<string, any>;
}

// Initialize design system
export function initDesignSystem(): void {
  console.log('Design System ready!');

  // Auto-initialize components with data attributes
  document.addEventListener('DOMContentLoaded', () => {
    // Initialize dropdowns
    document.querySelectorAll('[data-toggle="dropdown"]').forEach((el) => {
      // Initialize dropdown component
    });

    // Initialize modals
    document.querySelectorAll('[data-toggle="modal"]').forEach((el) => {
      // Initialize modal component
    });
  });
}

// Auto-init if in browser
if (typeof window !== 'undefined') {
  initDesignSystem();
}

This file serves as the public API for our JavaScript components. It exports essential utilities and makes them available for import in other parts of your application. The initDesignSystem function is key for automatically initializing components based on data attributes found in the HTML, making our Design System plug-and-play.

public/ts/utils/dom.ts - Utilitaires DOM

Utility functions are the unsung heroes of any front-end architecture. They abstract away common, repetitive tasks, making our component code cleaner and more readable. These DOM utilities help us manipulate the Document Object Model efficiently.

// DOM utilities

export function $( 
  selector: string,
  context: Document | Element = document
): Element | null {
  return context.querySelector(selector);
}

export function $( 
  selector: string,
  context: Document | Element = document
): NodeListOf<Element> {
  return context.querySelectorAll(selector);
}

export function createElement<K extends keyof HTMLElementTagNameMap>(
  tag: K,
  attributes: Partial<HTMLElementTagNameMap[K]> = {},
  content?: string
): HTMLElementTagNameMap[K] {
  const element = document.createElement(tag);

  Object.assign(element, attributes);

  if (content) {
    element.textContent = content;
  }

  return element;
}

export function addClass(element: Element, ...classes: string[]): void {
  element.classList.add(...classes);
}

export function removeClass(element: Element, ...classes: string[]): void {
  element.classList.remove(...classes);
}

export function toggleClass(element: Element, className: string): void {
  element.classList.toggle(className);
}

These functions provide a clean API for common DOM operations like selecting elements ($ and $), creating new elements (createElement), and managing CSS classes (addClass, removeClass, toggleClass). Using these utilities makes our component code more robust and easier to maintain.

Example of an Atom (e.g., public/ts/atoms/button.ts)

While not provided in the original example, an atom component in TypeScript might look something like this:

// Example: public/ts/atoms/button.ts

import { addClass, removeClass, toggleClass } from '../utils/dom';

export class Button {
  private element: HTMLButtonElement;

  constructor(element: HTMLButtonElement) {
    this.element = element;
  }

  // Example method: add primary class
  setPrimary(): void {
    addClass(this.element, 'btn--primary');
  }

  // Example method: disable button
  disable(): void {
    this.element.disabled = true;
    removeClass(this.element, 'btn--active');
  }

  // ... other button-specific methods
}

// Usage example (if needed for initialization):
// document.querySelectorAll('.btn').forEach(el => {
//   const button = new Button(el as HTMLButtonElement);
//   // Perform actions based on button type or attributes
// });

This demonstrates how a simple atom component can encapsulate its own behavior and expose methods for interaction. This level of abstraction is key to building a truly modular Design System.

These examples illustrate the practical application of our TypeScript setup within the Atomic Design framework, contributing to a clean and scalable front-end architecture.


πŸš€ Commandes de dΓ©marrage

Alright, you've got the setup, the structure, the configurations, and the scripts. Now, how do you actually use all this? Let's cover the essential commands you'll be running day-to-day to manage your front-end architecture and Design System.

πŸƒβ€β™‚οΈ Commandes essentielles

These are the workhorses of your development and build process. Make sure you're in your project's root directory in your terminal before running these.

  • npm run build

    # πŸš€ Build production (gΓ©nΓ¨re les fichiers .min.js et .min.css)
    npm run build
    

    This command kicks off the production build. It compiles your TypeScript and SCSS into optimized, minified files (.min.js, .min.css) and places them in the dist/ folder, including the latest/ and versioned subdirectories. This is what you'll run before deploying your application.

  • npm run compile

    # πŸ”§ Compilation dΓ©veloppement (gΓ©nΓ¨re les fichiers .js et .css avec sourcemap)
    npm run compile
    

    This command is for development. It compiles your TS and SCSS into readable, unminified files (.js, .css) along with source maps (.js.map, .css.map). Source maps are incredibly helpful for debugging as they allow you to see your original TypeScript or SCSS code in the browser's developer tools, even though the browser runs the compiled JavaScript/CSS.

  • npm run dev

    # πŸ‘€ Mode dΓ©veloppement (watch) - gΓ©nΓ¨re automatiquement les fichiers minifiΓ©s
    npm run dev
    

    This is your best friend during active development. It starts watch mode for both TypeScript and SCSS. Whenever you save changes to your source files, the relevant build scripts (build-ts.js or build-scss.js) are triggered automatically. It compiles them into the versioned dist/ directory, so you can see your changes reflected in the browser almost instantly. It's a fantastic way to speed up your workflow!

  • npm run lint

    # πŸ” Lint et format
    npm run lint
    

    This command runs the quality checks. It executes ESLint on your JavaScript/TypeScript files and Stylelint on your SCSS files, reporting any code style violations or potential errors based on our configurations (.eslintrc.js and .stylelintrc.json).

  • npm run format

    npm run format
    

    This command uses Prettier to automatically format all your code (JS, TS, SCSS) according to the rules defined in .prettierrc. Running this ensures consistent code style across the project.

  • npm run lint:fix

    npm run lint:fix
    

    This is like npm run lint, but it also attempts to automatically fix any fixable issues found by ESLint and Stylelint. It's a great way to quickly clean up your code.

  • npm run generate-icon-font

    # 🎨 Génération d'icon font
    npm run generate-icon-font
    

    This command executes the Python script to generate your icon font from SVG assets. Remember to make the script executable (chmod +x ./scripts/generate_icon_font.py) if you encounter permission issues.

πŸ—οΈ Installation rapide complΓ¨te

If you're starting a new project and want to set up this structure quickly, here's a set of commands to get you going:

# 1. CrΓ©er la structure de dossiers Atomic Design
mkdir -p public/scss/{abstracts/tokens,base,utilities,atoms,molecules,organisms,templates,pages,vendor}
mkdir -p public/ts/{atoms,molecules,organisms,templates,utils}

# 2. CrΓ©er les fichiers de base (SCSS et TS principaux)
touch public/scss/main.scss
touch public/scss/abstracts/{_index,_variables,_functions,_mixins}.scss
touch public/scss/abstracts/tokens/{_colors,_typography,_spacing,_breakpoints,_elevation,_border-radius,_transitions}.scss
touch public/scss/base/{_reset,_normalize,_typography,_global}.scss
touch public/scss/utilities/{_spacing,_colors,_layout,_typography,_responsive,_accessibility}.scss

# 3. CrΓ©er quelques fichiers d'exemple pour les niveaux Atomic Design (SCSS)
touch public/scss/atoms/{_button,_input,_label,_badge,_icon}.scss
touch public/scss/molecules/{_form-group,_search-box,_chip,_tooltip}.scss
touch public/scss/organisms/{_modal,_navbar,_form-wizard}.scss
touch public/scss/templates/{_layout-dashboard,_layout-auth}.scss
touch public/scss/pages/{_home,_dashboard}.scss

# 4. CrΓ©er les fichiers TypeScript correspondants
touch public/ts/main.ts
touch public/ts/atoms/{button,input,badge}.ts
touch public/ts/molecules/{form-group,tooltip}.ts
touch public/ts/organisms/{modal,navbar}.ts
touch public/ts/utils/{dom,events,validators}.ts

# 5. Installer les dΓ©pendances (assurez-vous que npm est configurΓ©)
npm install --save-dev @types/node chokidar concurrently esbuild eslint husky prettier sass stylelint stylelint-config-standard-scss typescript

# 6. Installer Husky hooks (doit Γͺtre fait aprΓ¨s l'installation des dΓ©pendances)
npx husky install
npx husky add .husky/pre-commit "npm run precommit"

# 7. Lancer le mode dΓ©veloppement
npm run dev

These commands provide a quick way to set up the foundational structure. Remember to populate the actual files with the code examples provided throughout this article to build out your Design System.

Mastering these commands will make your development process significantly more efficient, ensuring your front-end architecture is always in top shape.


πŸ“ Fichiers Γ  ignorer

When working with Git, it's crucial to tell it which files and directories should not be tracked. These are typically temporary files, build outputs, or sensitive information. Properly configuring your .gitignore file keeps your repository clean and focused on your source code. This is a standard practice for any front-end architecture.

.gitignore

Here's a .gitignore file tailored for this setup. Place this file in the root of your project directory.

# Dependencies
node_modules/

# Build output
dist/

# Logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# OS generated files
.DS_Store
.DS_Store?*
._*
.Spotlight-V100
.Trashes

# Environment variables
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# Husky hooks directory (managed by Husky itself)
.husky/_

# TypeScript cache
*.tsbuildinfo

Explanation of Entries:

  • node_modules/: This is the most important one. It contains all your installed npm packages. You never want to commit this directory; it can be easily reinstalled using npm install.
  • dist/: This is where our build scripts output the compiled CSS and JavaScript. These files are generated from your source code, so they don't need to be tracked directly in Git. Your build process will create them as needed.
  • Log files: Various log files generated by npm or other tools are ignored.
  • OS generated files: Files like .DS_Store created by macOS are irrelevant to the project and should be ignored.
  • Environment variables: Files containing sensitive information (API keys, database credentials) like .env should never be committed.
  • .husky/_: Husky manages its own internal files, which we don't need to track.
  • *.tsbuildinfo: TypeScript generates these files to speed up subsequent builds. They are safe to ignore.

By maintaining a clean .gitignore, you ensure that only your actual source code and configuration files are committed, keeping your version history focused and manageable. This is a small but critical detail for a well-organized front-end architecture and Design System.


⚠️ Points d'attention

Setting up a new front-end architecture can be exciting, but there are always a few potential pitfalls to watch out for. Being aware of these common issues can save you a lot of debugging time and ensure a smoother implementation of your Design System.

πŸ”§ Configuration requise

Before you dive headfirst into running all the commands, here are some things to double-check:

  • Adapter les chemins: The script paths (public/ts/main.ts, public/scss/main.scss, etc.) are based on the example structure. If your project has a different folder layout, you'll need to update these paths in the scripts/*.js files and potentially in tsconfig.json and package.json.
  • Installer Python: If you plan to use the icon font generation script (generate_icon_font.py), you'll need to have Python installed on your system. Make sure the fonttools and lxml libraries are also installed (pip install fonttools lxml).
  • Configurer les rΓ¨gles ESLint/Stylelint: The provided configurations are basic examples. You should review and adjust the ESLint and Stylelint rules to match your team's specific coding standards and project requirements. More complex projects might need additional plugins.
  • Tester les scripts un par un: Before using concurrently for commands like npm run build or npm run dev, it's a good idea to test each individual script first (e.g., node scripts/build-ts.js, node scripts/watch-scss.js). This helps isolate issues if something goes wrong.
  • VΓ©rifier les permissions pour le script Python: On Linux/macOS, executable scripts need execute permissions. You might need to run chmod +x ./scripts/generate_icon_font.py to make it runnable.

πŸ› οΈ Modifications des chemins

As mentioned, path adjustments are common. If you move your source files, for instance, from public/ts to src/ts, you'll need to update the references. Here’s where you’d typically look:

  • In scripts/build-ts.js and scripts/build-scss.js: The entryPoints for esbuild and the sass.compile path need to be updated.
    // Example for TypeScript build script:
    // Change this:
    // entryPoints: ['public/ts/main.ts'],
    // To this (if you moved your files):
    entryPoints: ['src/ts/main.ts'],
    
    // Example for SCSS build script:
    // Change this:
    // const result = sass.compile('public/scss/main.scss');
    // To this:
    // const result = sass.compile('src/scss/main.scss');
    
  • In tsconfig.json: The rootDir and include paths should reflect your new structure.
    {
      // ... other options
      "rootDir": "./src/ts", // Update this
      "include": ["src/ts/**/*"] // Update this
    }
    
  • In package.json: Any script that directly references file paths might need updating, though typically the scripts call the build files which contain the paths.

Being mindful of these details will help you adapt this front-end architecture setup to your specific project needs and ensure a successful implementation of your Design System.


🎯 Avantages du Design System From-Scratch

Building a Design System from scratch might sound like a lot of work, and it can be, but the benefits it offers to your front-end architecture are immense. Opting for a custom build rather than relying heavily on large third-party component libraries gives you unparalleled control and flexibility.

βœ… Pourquoi partir de zΓ©ro ?

Let's talk about why you might choose this path and the advantages it brings:

Avantage Description
🎯 Contrôle total You have complete control over every aspect of your components and build process. No need to fight against framework opinions or unexpected behaviors from external libraries. Your front-end architecture is truly yours.
πŸ”§ FlexibilitΓ© Adapt the system perfectly to your unique brand guidelines, design tokens, and specific project requirements. You can implement custom behaviors, animations, and integrations without limitations. Your Design System molds to your needs.
πŸš€ Performance By including only the code you actually need, you significantly reduce your application's bundle size. This leads to faster load times and a better user experience. No bloat from unused components or features found in large UI kits.
πŸ“ˆ Γ‰volutivitΓ© The modular nature, especially with Atomic Design and TypeScript, makes it easy to scale. Adding new components or features becomes a systematic process, ensuring consistency and maintainability as your project grows.
πŸ’‘ Apprentissage Building from scratch provides a deep understanding of the underlying technologies and principles of front-end development and component design. It's a fantastic learning experience for the team.
πŸ”’ SΓ©curitΓ© You're not introducing potential vulnerabilities from third-party dependencies that might not be actively maintained or audited. You control the security surface area.

Choosing a