| | |

Parcel 03 ๐Ÿ“ฆ Project Setup โ€” HTML entry points & source files

โฑ๏ธ Estimated read: 12 min | |

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

FilePurpose
src/index.htmlThe entry point; the asset graph root
src/index.jsThe JavaScript entry
src/styles.cssThe optional stylesheet
package.jsonThe dependencies and the source field

The HTML References

ElementDependency 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

FieldPurpose
sourceThe entry point(s) for the CLI
scripts.devThe development server
scripts.buildThe production build
devDependencies.parcelThe 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

PitfallWhy It HappensFix
The CSS is not processedThe entry is the JavaScriptUse the HTML entry
The images are not hashedNot referenced from the HTMLAdd the <img> tag or the CSS url()
The entry is not foundNo source field and no file argumentAdd the source field or the file argument
The module script is treated as classicNo type="module"Add the attribute
The multiple pages are not bundledNo multiple entriesUse 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

ItemValue
Entry pointThe HTML file for the web apps
Asset graph rootThe HTML file
Discovered referencesThe <script>, <link>, <img>, and <a>
Module script<script type="module">
package.json fieldsource
Multiple entriesThe source array or the CLI file list
Source directoryThe src/ convention, not a requirement
OutputThe 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 the async and the defer attributes, but the type="module" is the one that tells Parcel the script is an ES module .
  • The source field declares the entry once. The parcel and the parcel build commands 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 source array 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.


Was this helpful?


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!