Chapter 4: ES6 Modules
Introduction
ES6 modules allow you to organize code into separate files, with an explicit import/export system.
In PHP, you use require, include, or PSR-4 autoloading. In modern JavaScript, we use import and export.
Export
Named Export
Allows exporting multiple elements from a file:
// utils/math.js
// Export at declaration
export const PI = 3.14159;
export function add(a, b) {
return a + b;
}
export const multiply = (a, b) => a * b;
// OR grouped export at the end
const PI = 3.14159;
function add(a, b) { return a + b; }
const multiply = (a, b) => a * b;
export { PI, add, multiply };
Default Export
Only one default export per file. Generally used for the main component/class:
// components/Button.jsx
const Button = ({ label, onClick }) => {
return <button onClick={onClick}>{label}</button>;
};
export default Button;
// OR directly
export default function Button({ label, onClick }) {
return <button onClick={onClick}>{label}</button>;
}
Mixing Both
// services/api.js
// Default export: main API client
const apiClient = {
get: (url) => fetch(url).then(r => r.json()),
post: (url, data) => fetch(url, { method: 'POST', body: JSON.stringify(data) })
};
// Named exports: utilities
export const API_URL = "https://api.example.com";
export const handleError = (error) => console.error(error);
export default apiClient;
Import
Named Import
// Import named exports (braces required)
import { add, multiply } from './utils/math.js';
import { PI } from './utils/math.js';
// Rename on import
import { add as addition } from './utils/math.js';
// Import everything under a namespace
import * as MathUtils from './utils/math.js';
// Usage: MathUtils.add(1, 2), MathUtils.PI
Default Import
// Import default export (no braces)
import Button from './components/Button.jsx';
// The name is free (not linked to the name in the source file)
import MonBouton from './components/Button.jsx'; // OK
Mixed Import
// Default + named in the same import
import apiClient, { API_URL, handleError } from './services/api.js';
Import Paths
Relative Paths
// Same directory
import { helper } from './helper.js';
// Parent directory
import { config } from '../config.js';
// Subdirectory
import Button from './components/Button.jsx';
Package Imports (node_modules)
// npm packages - no relative path
import React from 'react';
import { useState, useEffect } from 'react';
import axios from 'axios';
Path Aliases (Vite/Webpack)
SmartMaker configures a src alias:
// Without alias (fragile relative paths)
import Button from '../../../components/Button.jsx';
// With alias (cleaner)
import Button from 'src/components/Button.jsx';
Configuration in vite.config.js:
export default defineConfig({
resolve: {
alias: {
'src': '/src'
}
}
});
Comparison with PHP
// PHP - PSR-4 autoloading
namespace App\Services;
use App\Models\User;
use App\Utils\Helper;
class UserService {
// ...
}
// JavaScript ES6
import User from 'src/models/User.js';
import { formatDate } from 'src/utils/helper.js';
export default class UserService {
// ...
}
| PHP | JavaScript |
|---|---|
namespace |
No direct equivalent (file = module) |
use App\Class |
import Class from 'path' |
new Class() |
new Class() or component <Class /> |
| Autoloading | Bundler (Vite/Webpack) resolves imports |
React File Organization
Typical SmartMaker Structure
src/
├── components/
│ ├── app/ # Providers, Router
│ │ ├── SmartCommonProvider/
│ │ │ └── index.jsx # export default SmartCommonProvider
│ │ └── Router/
│ │ └── index.jsx
│ │
│ ├── pages/
│ │ ├── public/
│ │ │ └── LoginPage/
│ │ │ └── index.jsx
│ │ └── private/
│ │ └── HomePage/
│ │ └── index.jsx
│ │
│ └── common/
│ ├── Button/
│ │ └── index.jsx
│ └── Card/
│ └── index.jsx
│
├── hooks/
│ └── useAuth.js
│
├── services/
│ └── api.js
│
└── utils/
└── format.js
Convention: index.jsx
When a directory contains index.jsx, you can import the directory directly:
// These two imports are equivalent
import Button from './components/common/Button/index.jsx';
import Button from './components/common/Button';
Barrel File (re-export)
A file that re-exports multiple modules:
// components/common/index.js
export { default as Button } from './Button';
export { default as Card } from './Card';
export { default as Modal } from './Modal';
// Usage
import { Button, Card, Modal } from 'src/components/common';
Dynamic Import
For code-splitting (lazy loading):
// Static import (loaded at startup)
import HeavyComponent from './HeavyComponent';
// Dynamic import (loaded when needed)
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
// Usage with Suspense
<Suspense fallback={<Loading />}>
<HeavyComponent />
</Suspense>
Exercises
Exercise 1: Create a Module
Create a file utils/string.js that exports:
- A constant
DEFAULT_LOCALE = "fr-FR" - A function
capitalize(str)that capitalizes the first letter - A default function
formatName(firstName, lastName)that returns "LASTNAME Firstname"
Solution:
// utils/string.js
export const DEFAULT_LOCALE = "fr-FR";
export function capitalize(str) {
if (!str) return '';
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
}
export default function formatName(firstName, lastName) {
return `${lastName.toUpperCase()} ${capitalize(firstName)}`;
}
Exercise 2: Import the Module
Import and use the created module:
// app.js
// 1. Import formatName (default)
// 2. Import capitalize and DEFAULT_LOCALE (named)
// 3. Display formatName("jean", "dupont")
// 4. Display capitalize("bonjour")
Solution:
// app.js
import formatName, { capitalize, DEFAULT_LOCALE } from './utils/string.js';
console.log(formatName("jean", "dupont")); // "DUPONT Jean"
console.log(capitalize("bonjour")); // "Bonjour"
console.log(DEFAULT_LOCALE); // "fr-FR"
Key Points to Remember
- Named export:
export const xorexport { x, y } - Default export:
export default X(only one per file) - Named import:
import { x, y } from './file'(braces) - Default import:
import X from './file'(no braces) - Alias:
import { x as alias } from './file' - Import all:
import * as Module from './file' - index.jsx: allows
import X from './folder'
Module 1 Summary
You now have the ES6+ JavaScript basics needed for React:
| Concept | Syntax |
|---|---|
| Variables | const, let |
| Destructuring | const { a, b } = obj |
| Spread | { ...obj }, [...arr] |
| Arrow functions | (x) => x * 2 |
| Default parameters | (x = 10) => ... |
| Template literals | `Hello ${name}` |
| Promises | .then(), .catch() |
| async/await | async function, await |
| Modules | import, export |
<- Previous Chapter | Back to Module | Next Module: Introduction to React ->