Feuille de chaleur de la parcelle¶
Parcel - L'outil de construction de configuration zéro
Parcel est un groupeur d'applications web, différencié par son expérience de développeur. Il offre des performances rapides en utilisant le traitement multicore, et nécessite une configuration zéro.
Sommaire¶
- [Installation] (#installation)
- [Pour commencer] (#getting-started)
- [Structure du projet] (#project-structure)
- Serveur de développement
- [Bâtiment pour la production] (#building-for-production)
- [Types d'ensemble] (#asset-types)
- [Transformations] (#transformations)
- [Doublure du code] (#code-splitting)
- [Remplacement du module hôte] (#hot-module-replacement)
- [variables environnementales] (#environment-variables)
- [Plugins] (#plugins)
- [Configuration] (#configuration)
- [Optimisation] (#optimization)
- [Objectifs] (#targets)
- [Cachage] (#caching)
- Cartes des sources
- [Analyse préliminaire] (#bundle-analysis)
- [Migration] (#migration)
- [Meilleures pratiques] (#best-practices)
Installation¶
Installation mondiale¶
# Install Parcel globally
npm install -g parcel
# Or with Yarn
yarn global add parcel
# Check version
parcel --version
Installation locale (recommandée)¶
# Initialize npm project
npm init -y
# Install Parcel as dev dependency
npm install --save-dev parcel
# Or with Yarn
yarn add --dev parcel
```_
### Paquet.json Scripts
```json
{
"scripts": {
"start": "parcel src/index.html",
"dev": "parcel src/index.html --open",
"build": "parcel build src/index.html",
"clean": "rm -rf dist .parcel-cache"
}
}
```_
## Commencer
### HTML de base Point d'entrée
```html
<!-- src/index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My Parcel App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="./index.js"></script>
</body>
</html>
Basic JavaScript Entrée¶
// src/index.js
import './styles.css';
console.log('Hello from Parcel!');
// Import and use a module
import { greet } from './utils';
greet('World');
CSS de base¶
/* src/styles.css */
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f0f0f0;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
Exécuter le serveur de développement¶
# Start development server
npm start
# Or with specific port
parcel src/index.html --port 3000
# Open browser automatically
parcel src/index.html --open
Structure du projet¶
Projet de parcelle typique¶
my-parcel-app/
├── src/
│ ├── index.html
│ ├── index.js
│ ├── styles.css
│ ├── components/
│ │ ├── Header.js
│ │ └── Footer.js
│ ├── assets/
│ │ ├── images/
│ │ └── fonts/
│ └── utils/
│ └── helpers.js
├── dist/ # Build output
├── .parcel-cache/ # Parcel cache
├── package.json
└── .gitignore
Points d'entrée multiples¶
Structure du projet de bibliothèque¶
Serveur de développement¶
Serveur de développement de base¶
# Start dev server
parcel src/index.html
# Custom port
parcel src/index.html --port 8080
# Custom host
parcel src/index.html --host 0.0.0.0
# HTTPS
parcel src/index.html --https
# Open browser
parcel src/index.html --open
Options de serveur de développement¶
# Disable HMR
parcel src/index.html --no-hmr
# Disable source maps
parcel src/index.html --no-source-maps
# Custom dist directory
parcel src/index.html --dist-dir build
# Watch additional files
parcel src/index.html --watch-dir src/data
Configuration de proxy¶
// package.json
{
"scripts": {
"start": "parcel src/index.html --port 3000"
},
"@parcel/resolver-default": {
"packageExports": true
}
}
Bâtiment pour la production¶
Construction de production de base¶
# Build for production
parcel build src/index.html
# Build with custom output directory
parcel build src/index.html --dist-dir build
# Build without source maps
parcel build src/index.html --no-source-maps
# Build without optimization
parcel build src/index.html --no-optimize
Configuration de construction¶
{
"scripts": {
"build": "parcel build src/index.html",
"build:analyze": "parcel build src/index.html --reporter @parcel/reporter-bundle-analyzer",
"build:stats": "parcel build src/index.html --reporter @parcel/reporter-bundle-buddy"
}
}
Optimisations de la production¶
# Enable scope hoisting
parcel build src/index.html --experimental-scope-hoisting
# Custom public URL
parcel build src/index.html --public-url /my-app/
# Detailed bundle report
parcel build src/index.html --detailed-report
Types d'actifs¶
JavaScript et TypeScript¶
// ES6 modules
import { helper } from './utils/helper.js';
// CommonJS
const lodash = require('lodash');
// Dynamic imports
const module = await import('./dynamic-module.js');
// TypeScript
import { Component } from './Component.ts';
CSS et préprocesseurs¶
/* CSS imports */
@import './normalize.css';
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap');
/* CSS modules */
.container {
composes: flex from './layout.css';
background: var(--primary-color);
}
// SCSS
@import './variables';
.component {
background: $primary-color;
&:hover {
background: darken($primary-color, 10%);
}
}
// Less
@import './variables.less';
.component {
background: @primary-color;
&:hover {
background: darken(@primary-color, 10%);
}
}
Images et biens¶
// Import images
import logo from './assets/logo.png';
import icon from './assets/icon.svg';
// Use in HTML
document.getElementById('logo').src = logo;
// CSS background images
.hero {
background-image: url('./assets/hero.jpg');
}
Polices¶
/* Font imports */
@font-face {
font-family: 'CustomFont';
src: url('./assets/fonts/custom-font.woff2') format('woff2'),
url('./assets/fonts/custom-font.woff') format('woff');
}
body {
font-family: 'CustomFont', sans-serif;
}
JSON et fichiers de données¶
// Import JSON
import data from './data.json';
import config from './config.json';
// Import text files
import template from './template.html';
import shader from './shader.glsl';
Transformations¶
Configuration de Babel¶
// .babelrc
{
"presets": [
["@babel/preset-env", {
"targets": {
"browsers": ["> 1%", "last 2 versions"]
}
}],
"@babel/preset-react"
],
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-syntax-dynamic-import"
]
}
PostCSS Configuration¶
// .postcssrc
{
"plugins": {
"autoprefixer": {
"grid": true
},
"cssnano": {
"preset": "default"
}
}
}
Configuration du script de type¶
// tsconfig.json
{
"compilerOptions": {
"target": "es2018",
"module": "esnext",
"lib": ["dom", "dom.iterable", "es6"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": [
"src"
]
}
Réagir à la configuration¶
// React component
import React from 'react';
import './Component.css';
export default function Component({ title }) {
return (
<div className="component">
<h1>{title}</h1>
</div>
);
}
Configuration de la vue¶
<!-- Vue component -->
<template>
<div class="component">
<h1>{{ title }}</h1>
</div>
</template>
<script>
export default {
props: ['title']
}
</script>
<style scoped>
.component {
padding: 20px;
}
</style>
Fractionnement du code¶
Importations dynamiques¶
// Dynamic import for code splitting
async function loadModule() {
const { default: Module } = await import('./heavy-module.js');
return new Module();
}
// React lazy loading
import React, { Suspense } from 'react';
const LazyComponent = React.lazy(() => import('./LazyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}
Séparation des ensembles¶
// Vendor bundle splitting
import React from 'react';
import ReactDOM from 'react-dom';
import lodash from 'lodash';
// App code
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
Séparation par parcours¶
// React Router with code splitting
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { Suspense, lazy } from 'react';
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
const Contact = lazy(() => import('./pages/Contact'));
function App() {
return (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/contact" component={Contact} />
</Switch>
</Suspense>
</Router>
);
}
Remplacement du module à chaud¶
HMR en JavaScript¶
// Enable HMR for a module
if (module.hot) {
module.hot.accept('./component.js', function() {
// Re-render component
render();
});
}
// HMR with state preservation
if (module.hot) {
module.hot.accept();
if (module.hot.data) {
// Restore state
restoreState(module.hot.data.state);
}
module.hot.dispose((data) => {
// Save state
data.state = getCurrentState();
});
}
Réagir¶
// React Fast Refresh (automatic with Parcel)
import React from 'react';
function App() {
const [count, setCount] = React.useState(0);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
export default App;
HMR CSS¶
/* CSS changes are automatically hot reloaded */
.component {
background: blue; /* Change this and see instant update */
padding: 20px;
border-radius: 8px;
}
Variables d'environnement¶
Utilisation des variables d'environnement¶
// Access environment variables
const apiUrl = process.env.API_URL || 'http://localhost:3000';
const isDevelopment = process.env.NODE_ENV === 'development';
console.log('API URL:', apiUrl);
console.log('Development mode:', isDevelopment);
.env Fichiers¶
Environnement Constructions¶
{
"scripts": {
"start": "NODE_ENV=development parcel src/index.html",
"build": "NODE_ENV=production parcel build src/index.html",
"build:staging": "NODE_ENV=staging parcel build src/index.html"
}
}
Greffons¶
Installation des plugins¶
# Install common plugins
npm install --save-dev @parcel/transformer-sass
npm install --save-dev @parcel/transformer-less
npm install --save-dev @parcel/transformer-stylus
npm install --save-dev @parcel/transformer-typescript
Configuration du plugin¶
// .parcelrc
{
"extends": "@parcel/config-default",
"transformers": {
"*.{ts,tsx}": ["@parcel/transformer-typescript-tsc"],
"*.scss": ["@parcel/transformer-sass"]
},
"reporters": ["@parcel/reporter-dev-server", "@parcel/reporter-bundle-analyzer"]
}
Plugins personnalisés¶
// parcel-plugin-custom.js
const { Transformer } = require('@parcel/plugin');
module.exports = new Transformer({
async transform({ asset }) {
const code = await asset.getCode();
// Transform the code
const transformedCode = customTransform(code);
asset.setCode(transformedCode);
return [asset];
}
});
Greffons populaires¶
# Bundle analyzer
npm install --save-dev @parcel/reporter-bundle-analyzer
# Service worker
npm install --save-dev parcel-plugin-sw-precache
# Compression
npm install --save-dev parcel-plugin-compress
# Clean dist
npm install --save-dev parcel-plugin-clean-dist
Configuration¶
Base .parcelrc¶
{
"extends": "@parcel/config-default",
"transformers": {
"*.{js,mjs,jsm,jsx,es6,cjs,ts,tsx}": [
"@parcel/transformer-js",
"@parcel/transformer-react-refresh-wrap"
]
}
}
Configuration avancée¶
{
"extends": "@parcel/config-default",
"resolvers": ["@parcel/resolver-default"],
"transformers": {
"*.{ts,tsx}": ["@parcel/transformer-typescript-tsc"],
"*.{js,jsx}": ["@parcel/transformer-js"],
"*.{css,scss,sass}": ["@parcel/transformer-sass", "@parcel/transformer-css"],
"*.{html,htm}": ["@parcel/transformer-html"]
},
"bundler": "@parcel/bundler-default",
"namers": ["@parcel/namer-default"],
"runtimes": ["@parcel/runtime-js", "@parcel/runtime-browser-hmr"],
"optimizers": {
"*.{js,mjs,jsm,jsx,ts,tsx}": ["@parcel/optimizer-terser"],
"*.{css,scss,sass}": ["@parcel/optimizer-css"]
},
"packagers": {
"*.html": "@parcel/packager-html",
"*.{js,mjs,jsm,jsx,ts,tsx}": "@parcel/packager-js",
"*.{css,scss,sass}": "@parcel/packager-css"
},
"compressors": {
"*": ["@parcel/compressor-gzip"]
},
"reporters": ["@parcel/reporter-dev-server"]
}
Configuration de la cible¶
// package.json
{
"targets": {
"default": {
"distDir": "dist"
},
"modern": {
"engines": {
"browsers": "Chrome 80"
}
},
"legacy": {
"engines": {
"browsers": "> 1%"
}
}
}
}
Optimisation¶
Optimisations de la production¶
# Build with optimizations
parcel build src/index.html
# Disable optimizations
parcel build src/index.html --no-optimize
# Enable experimental optimizations
parcel build src/index.html --experimental-scope-hoisting
Optimisation de la taille des ensembles¶
// Tree shaking (automatic with ES modules)
import { debounce } from 'lodash-es';
// Avoid importing entire libraries
import debounce from 'lodash/debounce';
// Use dynamic imports for large dependencies
async function loadChart() {
const { Chart } = await import('chart.js');
return Chart;
}
Optimisation de l'image¶
<!-- Automatic image optimization -->
<img src="./image.jpg" alt="Optimized image" />
<!-- WebP support -->
<picture>
<source srcset="./image.webp" type="image/webp">
<img src="./image.jpg" alt="Image with WebP fallback">
</picture>
CSS Optimisation¶
/* Automatic CSS optimization */
.component {
display: flex;
flex-direction: column;
gap: 1rem;
}
/* PostCSS plugins handle vendor prefixes */
.modern-feature {
backdrop-filter: blur(10px);
}
Objectifs¶
Objectifs du navigateur¶
Node.js Cible¶
Objectifs de la bibliothèque¶
Cibles multiples¶
{
"targets": {
"modern": {
"engines": {
"browsers": "Chrome 80"
},
"distDir": "dist/modern"
},
"legacy": {
"engines": {
"browsers": "> 1%"
},
"distDir": "dist/legacy"
}
}
}
Cache¶
Construire le cache¶
# Cache location
.parcel-cache/
# Clear cache
rm -rf .parcel-cache
# Disable cache
parcel build src/index.html --no-cache
Cachement HTTP¶
// Automatic content hashing for long-term caching
// Output: main.a1b2c3d4.js
// Service worker for caching
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
Configuration de cache¶
Cartes sources¶
Configuration de la carte source¶
# Enable source maps (default in development)
parcel src/index.html
# Disable source maps
parcel src/index.html --no-source-maps
# Production source maps
parcel build src/index.html --source-maps
Types de cartes sources¶
// .parcelrc
{
"extends": "@parcel/config-default",
"optimizers": {
"*.js": {
"sourceMap": {
"inline": false,
"inlineSources": true
}
}
}
}
Analyse de l'ensemble¶
Analyseur de groupe¶
# Install bundle analyzer
npm install --save-dev @parcel/reporter-bundle-analyzer
# Build with analyzer
parcel build src/index.html --reporter @parcel/reporter-bundle-analyzer
Groupe Buddy¶
# Install bundle buddy
npm install --save-dev @parcel/reporter-bundle-buddy
# Generate bundle buddy report
parcel build src/index.html --reporter @parcel/reporter-bundle-buddy
Analyse personnalisée¶
// analyze-bundle.js
const fs = require('fs');
const path = require('path');
function analyzeBundles() {
const distDir = path.join(__dirname, 'dist');
const files = fs.readdirSync(distDir);
files.forEach(file => {
const filePath = path.join(distDir, file);
const stats = fs.statSync(filePath);
console.log(`${file}: ${(stats.size / 1024).toFixed(2)} KB`);
});
}
analyzeBundles();
Migrations¶
À partir de Webpack¶
// webpack.config.js (remove this file)
// Parcel handles most webpack functionality automatically
// Update package.json scripts
{
"scripts": {
"start": "parcel src/index.html",
"build": "parcel build src/index.html"
}
}
De l'application Create React¶
# Remove react-scripts
npm uninstall react-scripts
# Install Parcel
npm install --save-dev parcel
# Update scripts
{
"scripts": {
"start": "parcel public/index.html",
"build": "parcel build public/index.html"
}
}
De Rollup¶
// Remove rollup.config.js
// Update package.json
{
"source": "src/index.js",
"main": "dist/index.js",
"scripts": {
"build": "parcel build"
}
}
Liste de contrôle des migrations¶
- Supprime les anciens fichiers de configuration des paquets
- Mettre à jour les scripts paquet.json
- Installer la parcelle et enlever l'ancien paqueteur
- Mettre à jour les chemins d'importation si nécessaire
- Configurer .parcelrc si des transformations personnalisées sont nécessaires
- Développement d'essais et constructions de production
- Mettre à jour les pipelines CI/CD
Meilleures pratiques¶
Organisation du projet¶
# Recommended structure
src/
├── index.html # Entry point
├── index.js # Main JavaScript
├── styles/ # Global styles
├── components/ # Reusable components
├── pages/ # Page components
├── utils/ # Utility functions
├── assets/ # Static assets
└── types/ # TypeScript types
Meilleures pratiques en matière de rendement¶
- Utiliser les importations dynamiques pour le fractionnement des codes
- Optimiser les images avec les formats appropriés
- ** Minimiser la taille du faisceau** avec tremblement d'arbre
- Contraction automatique pour les constructions de production
- Utilisez le hachage du contenu pour le cache
Meilleures pratiques de développement¶
- Utiliser HMR pour un développement plus rapide
- Activer les cartes sources pour le débogage
- Configurer le lintage avec ESLint et Prettier
- Utilisez TypeScript pour une meilleure expérience de développement
- Set up testing avec Jest ou d'autres cadres
Meilleures pratiques de production¶
- Optimiser pour les navigateurs cibles avec la liste des navigateurs
- Activer toutes les optimisations dans les constructions de production
- Utiliser les variables d'environnement pour la configuration
- ** Taille du faisceau de moniteur** avec outils d'analyse
- Construits d'essai avant déploiement
Résumé¶
Parcel est un outil de construction de configuration zéro qui fournit une excellente expérience de développeur avec une configuration minimale. Les principales caractéristiques sont les suivantes :
- ** Configuration de Zero**: Fonctionne hors de la boîte pour la plupart des projets
- Fast Builds: Utilise le traitement et la mise en cache multicore
- Remplacement du module hôte: mises à jour instantanées pendant le développement
- Manipulation de l'ensemble: Prend en charge tous les types de fichiers courants
- Doublure du code: fractionnement automatique et manuel du code
- Tree Shaking: supprime automatiquement le code inutilisé
- Cartes d'origine: prise en charge de la carte d'origine intégrée
- Optimisation: Optimisations automatiques de la production
En tirant parti de la simplicité et de la puissance de Parcel, vous pouvez vous concentrer sur la construction de votre application plutôt que sur la configuration des outils de construction, tout en ayant la flexibilité de personnaliser au besoin.