Parcel 03 ๐ฆ Project Setup โ HTML entry points & source files
Parcel project setup is deliberately minimal. There is no configuration file to write and no directory structure to obey. The setup consists of one HTML file, one or more source files referenced from it, and a package.json that points Parcel at the HTML entry. The previous chapter covered the CLI commands; this chapter covers the file layout that those commands operate on, and the way Parcel follows the HTML references to discover the entire application.
The HTML file is the conventional entry point for a web application, and Parcel treats it as the root of the asset graph. The <script> and <link> tags inside the HTML are the first dependencies Parcel discovers, and each referenced file becomes an asset that Parcel transforms and follows in turn . A JavaScript entry point works for a library, but it cannot discover the CSS and image dependencies that the HTML references. The HTML entry is the setup decision that determines whether Parcel sees the whole application or only the JavaScript portion of it.
Key point: Parcel accepts any file type as an entry, but the HTML file is the recommended starting point for web applications because it references the JavaScript, the CSS, and the images that the application needs . The package.json source field is the mechanism for declaring the entry once, so the CLI commands do not need to repeat the file path .
Why the project setup requires the HTML entry
The dependency-discovery problem.
A Parcel build starts from the entry and follows every reference it finds. An HTML entry gives Parcel three kinds of references to follow: the <script> tags lead to the JavaScript and its imports, the <link rel="stylesheet"> tags lead to the CSS and its @import and url() references, and the <img> tags lead to the image files . A JavaScript entry gives Parcel only the first kind. The CSS and the images would need to be imported from the JavaScript, which is a workaround, not the natural structure of a web application.
The output-rewriting problem.
Parcel rewrites the URLs in the HTML to point to the hashed output files. The <script src="./src/index.js"> becomes a reference to the bundled and hashed JavaScript, and the <link href="./styles.css"> becomes a reference to the bundled and hashed CSS . This rewriting only happens for the references Parcel discovers. If the CSS is not referenced from the HTML and not imported from the JavaScript, it is not part of the asset graph, and it is not processed or rewritten.
The source-field problem.
The package.json source field declares the entry points for the project. When the field is present, the parcel command without a file argument reads it and uses those entries . This is the mechanism that keeps the entry declaration in one place, so the dev and build scripts in the package.json do not need to repeat the path. The field can be a single string or an array for multiple entries.
a. The minimal project structure
The minimal Parcel web application has an HTML file, a JavaScript file, and a package.json. The CSS and the images are optional additions that the HTML can reference.
my-app/
โโโ src/
โ โโโ index.html # The entry point
โ โโโ index.js # The JavaScript entry
โ โโโ styles.css # The optional stylesheet
โ โโโ logo.png # The optional image
โโโ package.json # The dependencies and the source field
The src/ directory is a convention, not a requirement. Parcel does not care where the files are, only that the HTML references them correctly. The HTML file can be in the project root, and the source files can be in the src/ directory, and the relative paths in the HTML connect them.
The index.html references the JavaScript and the stylesheet.
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="./styles.css" />
</head>
<body>
<div id="app"></div>
<img src="./logo.png" alt="Logo" />
<script type="module" src="./index.js"></script>
</body>
</html>
The type="module" attribute tells Parcel that the script is an ES module. Parcel supports the async and the defer attributes, but the type="module" is the one that signals the module semantics . The <link> and the <img> references are discovered in the same pass, and the CSS and the image become assets in the graph.
b. The JavaScript and the CSS sources
The JavaScript file is the application logic. Parcel transforms it with the SWC-based transformer, and it follows the import statements to the other JavaScript files and the node_modules packages.
// src/index.js
import { createApp } from './app'
const app = createApp()
app.mount('#app')
The import { createApp } from './app' is a relative import, and Parcel resolves it to the src/app.js file. The createApp file may import other files, and the graph grows from there. The bare imports like import React from 'react' are resolved through the node_modules, and the React package becomes a dependency in the graph.
The CSS file is transformed by the CSS transformer, and its @import and url() references become dependencies.
/* src/styles.css */
@import './reset.css';
body {
background: url('./bg.png');
}
The @import './reset.css' is a CSS dependency, and the url('./bg.png') is an asset dependency. Both are discovered during the transform phase, and both become nodes in the asset graph . The reset.css is transformed in turn, and the bg.png is processed by the image transformer and emitted as a hashed asset.
c. The package.json and the source field
The package.json declares the dependency on Parcel and the source field that points to the HTML entry.
{
"name": "my-parcel-app",
"source": "src/index.html",
"scripts": {
"dev": "parcel",
"build": "parcel build"
},
"devDependencies": {
"parcel": "^2.0.0"
}
}
The source field replaces the file argument in the CLI commands. The parcel and the parcel build commands read the source field and use the src/index.html as the entry . The dev script starts the development server, and the build script performs the production build.
The source field can also declare the multiple entries.
{
"source": ["src/index.html", "src/about.html"]
}
The array form is the mechanism for the multi-page applications. Each entry becomes a separate bundle, and the shared dependencies between the entries are deduplicated into the shared bundles . The parcel src/index.html src/about.html command achieves the same result without the source field.
Complete Example Session
# ============================================
# PART 1: THE PROJECT DIRECTORY
# ============================================
mkdir my-parcel-app && cd my-parcel-app
# ============================================
# PART 2: THE PACKAGE.JSON
# ============================================
cat > package.json <<'EOF'
{
"name": "my-parcel-app",
"source": "src/index.html",
"scripts": {
"dev": "parcel",
"build": "parcel build"
}
}
EOF
# ============================================
# PART 3: THE HTML ENTRY
# ============================================
mkdir src
cat > src/index.html <<'EOF'
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="./styles.css" />
</head>
<body>
<div id="app"></div>
<script type="module" src="./index.js"></script>
</body>
</html>
EOF
# ============================================
# PART 4: THE JAVASCRIPT SOURCE
# ============================================
cat > src/index.js <<'EOF'
import { greet } from './greet'
document.getElementById('app').textContent = greet('Parcel')
EOF
cat > src/greet.js <<'EOF'
export function greet(name) {
return `Hello, ${name}`
}
EOF
# ============================================
# PART 5: THE CSS SOURCE
# ============================================
cat > src/styles.css <<'EOF'
body {
font-family: sans-serif;
}
EOF
# ============================================
# PART 6: THE INSTALL AND THE DEV SERVER
# ============================================
npm install --save-dev parcel
npm run dev
# ============================================
# PART 7: THE PRODUCTION BUILD
# ============================================
npm run build
ls dist/
# The index.html, the hashed JS, and the hashed CSS
The seven parts demonstrate the project setup: the package, the HTML entry, the JavaScript and the CSS sources, the install, the dev server, and the production build.
Quick Reference
The Project Files
| File | Purpose |
|---|---|
src/index.html | The entry point; the asset graph root |
src/index.js | The JavaScript entry |
src/styles.css | The optional stylesheet |
package.json | The dependencies and the source field |
The HTML References
| Element | Dependency Type |
|---|---|
<script type="module"> | The JavaScript or the TypeScript |
<link rel="stylesheet"> | The CSS, the SASS, or the Less |
<img src> | The image asset |
<a href> | The linked page (a separate entry) |
The package.json Fields
| Field | Purpose |
|---|---|
source | The entry point(s) for the CLI |
scripts.dev | The development server |
scripts.build | The production build |
devDependencies.parcel | The Parcel package |
Best Practices
โ Do This:
# Use the HTML entry for the web apps
# The CSS and the images are discovered from the HTML # โ
# Use the source field to declare the entry once
"source": "src/index.html" # โ
# Use the type="module" on the script tag
<script type="module" src="./index.js"></script> # โ
# Reference the stylesheet with the link tag
<link rel="stylesheet" href="./styles.css" /> # โ
# Use the relative paths from the HTML file
# The paths are resolved relative to the HTML location # โ
โ Don’t Do This:
# Use the JavaScript entry for a web app
# The CSS and the images are not discovered # โ
# Omit the source field and the file argument
parcel # Parcel does not know what to build # โ
# Use the classic script tag without type="module"
<script src="./index.js"></script> # The module semantics lost # โ
# Reference the files with the absolute paths
<link href="/src/styles.css" /> # The path resolution differs # โ
# Put the HTML in the public/ directory
public/index.html # The entry is not processed as the HTML # โ
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| The CSS is not processed | The entry is the JavaScript | Use the HTML entry |
| The images are not hashed | Not referenced from the HTML | Add the <img> tag or the CSS url() |
| The entry is not found | No source field and no file argument | Add the source field or the file argument |
| The module script is treated as classic | No type="module" | Add the attribute |
| The multiple pages are not bundled | No multiple entries | Use the source array or the CLI file list |
Real-World Examples
1. The HTML entry
<script type="module" src="./index.js"></script>
2. The stylesheet reference
<link rel="stylesheet" href="./styles.css" />
3. The image reference
<img src="./logo.png" alt="Logo" />
4. The source field
{ "source": "src/index.html" }
5. The multiple entries
{ "source": ["src/index.html", "src/about.html"] }
6. The JavaScript entry
import { createApp } from './app'
7. The CSS import
@import './reset.css';
8. The CSS url reference
background: url('./bg.png');
9. The package scripts
{ "scripts": { "dev": "parcel", "build": "parcel build" } }
10. The build output
ls dist/
# index.html, index.[hash].js, index.[hash].css
Visual
The Asset Graph from the HTML Entry
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ THE HTML ENTRY IS THE ROOT OF THE ASSET GRAPH โ
โ โ
โ src/index.html โ
โ โโโ <link href="./styles.css"> โ
โ โ โโโ @import './reset.css' โ
โ โ โโโ url('./bg.png') โ
โ โโโ <script src="./index.js"> โ
โ โ โโโ import './greet' โ
โ โ โโโ import 'react' โ
โ โโโ <img src="./logo.png"> โ
โ โ
โ Every discovered file becomes an asset in the graph. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The Source Field
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ THE source FIELD REPLACES THE CLI FILE ARGUMENT โ
โ โ
โ package.json: โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ { "source": "src/index.html" } โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ
โ โผ โ
โ parcel โ the dev server for src/index.html โ
โ parcel build โ the production build for src/index.html โ
โ โ
โ The entry is declared once, not repeated in every command. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The HTML Reference Types
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ PARCEL DISCOVERS THE DEPENDENCIES FROM THE HTML ELEMENTS โ
โ โ
โ <script type="module" src="..."> โ the JS or the TS โ
โ <link rel="stylesheet" href="..."> โ the CSS or the SASS โ
โ <img src="..."> โ the image asset โ
โ <a href="..."> โ the linked page โ
โ โ
โ The script and the link are the primary dependencies. โ
โ The images and the links are the secondary dependencies. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| Item | Value |
|---|---|
| Entry point | The HTML file for the web apps |
| Asset graph root | The HTML file |
| Discovered references | The <script>, <link>, <img>, and <a> |
| Module script | <script type="module"> |
package.json field | source |
| Multiple entries | The source array or the CLI file list |
| Source directory | The src/ convention, not a requirement |
| Output | The hashed bundles in dist/ |
Key takeaways:
- The HTML file is the recommended entry for the web apps. Parcel follows the
<script>,<link>, and<img>references to build the asset graph. A JavaScript entry misses the CSS and the image dependencies . - The
type="module"attribute signals the module semantics. Parcel supports theasyncand thedeferattributes, but thetype="module"is the one that tells Parcel the script is an ES module . - The
sourcefield declares the entry once. Theparceland theparcel buildcommands read the field when no file argument is given. The field can be a string or an array for the multiple entries . - The CSS and the images are discovered from the HTML. The
<link>and the<img>references become assets in the graph, and Parcel rewrites the URLs to the hashed output files . - The
src/directory is a convention, not a requirement. Parcel does not care where the files are, only that the HTML references them with the correct relative paths. - The multiple entries produce the separate bundles. The shared dependencies between the entries are deduplicated. The
sourcearray or the CLI file list declares the entries .
Remember: The Parcel project setup is the HTML entry, the source files it references, and the package.json source field. The HTML is the root of the asset graph, and every reference inside it becomes a dependency that Parcel transforms and follows. The source field declares the entry once, so the CLI commands stay short. The result is the minimal project structure that Parcel can build from the first command, without a configuration file describing the pipeline.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!