Modern Front-end Architecture: A Design System Approach
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
- Vue d'ensemble
- Installation des dΓ©pendances
- Structure des dossiers (Atomic Design)
- Scripts de build
- Configuration des outils
- Scripts package.json
- MΓ©thodologie Atomic Design
- Commandes de dΓ©marrage
- Configuration Git
- 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.
- π¬ 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/
andpublic/ts/atoms/
folders, you'll find things like buttons, inputs, and badges. - π§ͺ 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/
andpublic/ts/molecules/
folders will hold these, like aform-group
or asearch-box
. - π¦ 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/
andpublic/ts/organisms/
for things likemodal
ornavbar
. - π 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
orauth-layout
inscss/templates/
andpublic/ts/templates/
. - π 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 yourpackage.json
. For example, if yourpackage.json
has"version": "1.0.0"
, youβll see av.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 extendingstylelint-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 usesconcurrently
to runbuild:ts
andbuild:scss
in parallel, creating optimized, minified assets in thedist/
folder with versioning.build:ts
&build:scss
: These are the individual scripts that execute our TypeScript and SCSS production compilation logic defined in thescripts/
directory.compile
: This command is for development. It runscompile:ts
andcompile: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 runsdev:ts
anddev: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?
npx husky add .husky/pre-commit
: This command tells Husky to create or update thepre-commit
file inside the.husky/
directory."npm run precommit"
: This is the command that will be executed when thepre-commit
hook is triggered. We've defined aprecommit
script in ourpackage.json
that runsnpm 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 orcomponent-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 thedist/
folder, including thelatest/
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
orbuild-scss.js
) are triggered automatically. It compiles them into the versioneddist/
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 usingnpm 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 thescripts/*.js
files and potentially intsconfig.json
andpackage.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 thefonttools
andlxml
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 likenpm run build
ornpm 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
andscripts/build-scss.js
: TheentryPoints
foresbuild
and thesass.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
: TherootDir
andinclude
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