Parcel Cheatsheet¶
Parcel - The Zero Configuration Build Tool
Parcel is a web application bundler, differentiated by its developer experience. It offers blazing fast performance utilizing multicore processing, and requires zero configuration.
Table of Contents¶
- Installation
- Getting Started
- Project Structure
- Development Server
- Building for Production
- Asset Types
- Transformations
- Code Splitting
- Hot Module Replacement
- Environment Variables
- Plugins
- Configuration
- Optimization
- Targets
- Caching
- Source Maps
- Bundle Analysis
- Migration
- Best Practices
Installation¶
Global Installation¶
# Install Parcel globally
npm install -g parcel
# Or with Yarn
yarn global add parcel
# Check version
parcel --version
Local Installation (Recommended)¶
# Initialize npm project
npm init -y
# Install Parcel as dev dependency
npm install --save-dev parcel
# Or with Yarn
yarn add --dev parcel
Package.json Scripts¶
{
"scripts": {
"start": "parcel src/index.html",
"dev": "parcel src/index.html --open",
"build": "parcel build src/index.html",
"clean": "rm -rf dist .parcel-cache"
}
}
Getting Started¶
Basic HTML Entry Point¶
<!-- 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 Entry¶
// src/index.js
import './styles.css';
console.log('Hello from Parcel!');
// Import and use a module
import { greet } from './utils';
greet('World');
Basic CSS¶
/* 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);
}
Run Development Server¶
# Start development server
npm start
# Or with specific port
parcel src/index.html --port 3000
# Open browser automatically
parcel src/index.html --open
Project Structure¶
Typical Parcel Project¶
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
Multiple Entry Points¶
Library Project Structure¶
Development Server¶
Basic Development Server¶
# 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
Development Server Options¶
# 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
Proxy Configuration¶
// package.json
{
"scripts": {
"start": "parcel src/index.html --port 3000"
},
"@parcel/resolver-default": {
"packageExports": true
}
}
Building for Production¶
Basic Production Build¶
# 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
Build Configuration¶
{
"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"
}
}
Production Optimizations¶
# 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
Asset Types¶
JavaScript and 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 and Preprocessors¶
/* 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 and Assets¶
// 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');
}
Fonts¶
/* 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 and Data Files¶
// 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¶
Babel Configuration¶
// .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"
}
}
}
TypeScript Configuration¶
// 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"
]
}
React Configuration¶
// React component
import React from 'react';
import './Component.css';
export default function Component({ title }) {
return (
<div className="component">
<h1>{title}</h1>
</div>
);
}
Vue Configuration¶
<!-- Vue component -->
<template>
<div class="component">
<h1>{{ title }}</h1>
</div>
</template>
<script>
export default {
props: ['title']
}
</script>
<style scoped>
.component {
padding: 20px;
}
</style>
Code Splitting¶
Dynamic Imports¶
// 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>
);
}
Bundle Splitting¶
// 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'));
Route-based Splitting¶
// 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>
);
}
Hot Module Replacement¶
HMR in 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();
});
}
React HMR¶
// 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;
CSS HMR¶
/* CSS changes are automatically hot reloaded */
.component {
background: blue; /* Change this and see instant update */
padding: 20px;
border-radius: 8px;
}
Environment Variables¶
Using Environment Variables¶
// 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 Files¶
Environment-specific Builds¶
{
"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"
}
}
Plugins¶
Installing 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
Plugin Configuration¶
// .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"]
}
Custom Plugins¶
// 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];
}
});
Popular Plugins¶
# 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¶
Basic .parcelrc¶
{
"extends": "@parcel/config-default",
"transformers": {
"*.{js,mjs,jsm,jsx,es6,cjs,ts,tsx}": [
"@parcel/transformer-js",
"@parcel/transformer-react-refresh-wrap"
]
}
}
Advanced Configuration¶
{
"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"]
}
Target Configuration¶
// package.json
{
"targets": {
"default": {
"distDir": "dist"
},
"modern": {
"engines": {
"browsers": "Chrome 80"
}
},
"legacy": {
"engines": {
"browsers": "> 1%"
}
}
}
}
Optimization¶
Production Optimizations¶
# 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
Bundle Size Optimization¶
// 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;
}
Image Optimization¶
<!-- 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 Optimization¶
/* Automatic CSS optimization */
.component {
display: flex;
flex-direction: column;
gap: 1rem;
}
/* PostCSS plugins handle vendor prefixes */
.modern-feature {
backdrop-filter: blur(10px);
}
Targets¶
Browser Targets¶
Node.js Target¶
Library Target¶
Multiple Targets¶
{
"targets": {
"modern": {
"engines": {
"browsers": "Chrome 80"
},
"distDir": "dist/modern"
},
"legacy": {
"engines": {
"browsers": "> 1%"
},
"distDir": "dist/legacy"
}
}
}
Caching¶
Build Caching¶
# Cache location
.parcel-cache/
# Clear cache
rm -rf .parcel-cache
# Disable cache
parcel build src/index.html --no-cache
HTTP Caching¶
// Automatic content hashing for long-term caching
// Output: main.a1b2c3d4.js
// Service worker for caching
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
Cache Configuration¶
Source Maps¶
Source Map Configuration¶
# 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
Source Map Types¶
// .parcelrc
{
"extends": "@parcel/config-default",
"optimizers": {
"*.js": {
"sourceMap": {
"inline": false,
"inlineSources": true
}
}
}
}
Bundle Analysis¶
Bundle Analyzer¶
# Install bundle analyzer
npm install --save-dev @parcel/reporter-bundle-analyzer
# Build with analyzer
parcel build src/index.html --reporter @parcel/reporter-bundle-analyzer
Bundle 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
Custom Analysis¶
// 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();
Migration¶
From 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"
}
}
From Create React App¶
# 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"
}
}
From Rollup¶
// Remove rollup.config.js
// Update package.json
{
"source": "src/index.js",
"main": "dist/index.js",
"scripts": {
"build": "parcel build"
}
}
Migration Checklist¶
- Remove old bundler configuration files
- Update package.json scripts
- Install Parcel and remove old bundler
- Update import paths if needed
- Configure .parcelrc if custom transformations needed
- Test development and production builds
- Update CI/CD pipelines
Best Practices¶
Project Organization¶
# 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
Performance Best Practices¶
- Use dynamic imports for code splitting
- Optimize images with appropriate formats
- Minimize bundle size with tree shaking
- Enable compression for production builds
- Use content hashing for caching
Development Best Practices¶
- Use HMR for faster development
- Enable source maps for debugging
- Configure linting with ESLint and Prettier
- Use TypeScript for better development experience
- Set up testing with Jest or other frameworks
Production Best Practices¶
- Optimize for target browsers with browserslist
- Enable all optimizations in production builds
- Use environment variables for configuration
- Monitor bundle size with analysis tools
- Test builds before deployment
Summary¶
Parcel is a zero-configuration build tool that provides an excellent developer experience with minimal setup. Key features include:
- Zero Configuration: Works out of the box for most projects
- Fast Builds: Utilizes multicore processing and caching
- Hot Module Replacement: Instant updates during development
- Asset Handling: Supports all common file types
- Code Splitting: Automatic and manual code splitting
- Tree Shaking: Removes unused code automatically
- Source Maps: Built-in source map support
- Optimization: Automatic production optimizations
By leveraging Parcel's simplicity and power, you can focus on building your application rather than configuring build tools, while still having the flexibility to customize when needed.