Parcel 29 ๐ฆ Deployment โ Static hosting & server configuration
Parcel produces a static bundle. The parcel build command reads the entry fileโusually an index.htmlโand writes the optimized output to the dist directory. The deployment is the process of serving that dist directory from a static host, and the server configuration is the set of rules that tells the host how to serve the files: the build command, the publish directory, and the rewrite rule for a single-page application. The build is the same regardless of the host. The configuration is host-specific, and the two settings that cause the most deployment failures are the publish directory and the public URL.
The publish directory is dist by default. Parcel’s documentation states that the implicit default target has the output folder ~/dist/, and the --dist-dir flag or the targets.*.distDir field in package.json can override it . A host that is configured to publish the project root instead of dist will serve the source files, not the bundle, and the application will fail to load. The public URL is the second setting. Parcel generates absolute paths for the assets by default, and a deployment under a subpathโa GitHub Pages project site at /repo-name/, for exampleโneeds the --public-url ./ flag to produce relative paths . Without the flag, the assets point to the domain root, and the subpath deployment loads a blank page.
Key point: The build command is parcel build <entry>, the publish directory is dist, and the public URL is the flag that makes the asset paths work under a subpath. The single-page application needs a rewrite rule that serves index.html for unmatched routes, and the rule is host-specific.
Why the deployment configuration is host-specific
The build output is the same. Parcel writes the bundle to dist regardless of the host. The parcel build command bundles, minifies, and content-hashes the output, and the dist directory contains the index.html, the hashed JavaScript and CSS, and the copied static assets . The host does not change the build; it changes how the build is served.
The publish directory problem. A static host needs to know which directory contains the files to serve. The answer is dist, but the host’s default is often the project root. A Netlify configuration sets publish = "dist", and a Vercel configuration sets distDir: "dist" . A host that is configured to serve the root will serve the source index.html, which references the source files, not the bundle. The error is a blank page or a 404 on the asset paths.
The public URL problem. Parcel’s default asset paths are absolute (/index.hash.js). A deployment at the domain root works because the absolute path resolves to the correct location. A deployment under a subpath (/repo-name/) does not, because /index.hash.js points to the domain root, not the subpath. The --public-url ./ flag produces relative paths (./index.hash.js), which resolve against the current directory and work under any subpath . The flag is the fix for the GitHub Pages and subdirectory deployments.
The SPA rewrite problem. A single-page application has one index.html and a client-side router. A request for /dashboard does not match a file on disk, and the static host returns a 404 before the router can run. The rewrite rule serves index.html for unmatched paths, and the router reads the URL and renders the correct component. The rule is a _redirects file on Netlify and Cloudflare Pages, a rewrites array in vercel.json, and a try_files directive on Nginx .
a. The build configuration and the public URL
The package.json scripts are the build configuration. The build script runs parcel build with the entry file and, if needed, the --public-url flag.
// package.json โ the build script for a root deployment
{
"scripts": {
"build": "parcel build src/index.html"
}
}
The root deployment uses the default absolute paths. The dist directory is the publish directory, and the asset paths resolve from the domain root.
// package.json โ the build script for a subpath deployment
{
"scripts": {
"build": "parcel build src/index.html --public-url ./"
}
}
The --public-url ./ flag produces relative paths. The dist directory can be deployed to /repo-name/ on GitHub Pages, and the assets resolve against the subpath . The flag is the difference between a working subpath deployment and a blank page.
The source field in package.json is the alternative to passing the entry file in the script. The field tells Parcel where the entry HTML lives, and the parcel build command reads it . The main field inference is the trap: Parcel reads the main field and treats the project as a library if the field is present. A web application should set "targets": { "main": false } to disable the inference, or remove the main field entirely .
b. The host configuration and the SPA rewrite
The host configuration has two parts: the build settings and the rewrite rule. The build settings tell the host how to run the build and where the output is. The rewrite rule tells the host how to serve the SPA routes.
Netlify. The netlify.toml file sets the build command and the publish directory. The [[redirects]] section is the SPA rewrite.
# netlify.toml โ the build and rewrite configuration
[build]
command = "parcel build src/index.html"
publish = "dist"
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
The publish = "dist" is the directory that Netlify serves. The status = 200 makes the rewrite a rewrite rather than a redirect . The _redirects file in the dist directory is the alternative for a project that does not use netlify.toml.
Vercel. The vercel.json file sets the build and the rewrite. The builds section points to the entry and the distDir. The routes section is the SPA fallback.
// vercel.json โ the build and rewrite configuration
{
"builds": [
{
"src": "src/index.html",
"use": "@vercel/static-build",
"config": { "distDir": "dist" }
}
],
"routes": [
{ "handle": "filesystem" },
{ "src": "/.*", "dest": "/index.html" }
]
}
The handle: "filesystem" route serves the static files first. The second route is the fallback that serves index.html for the unmatched paths . The distDir is the directory that Vercel serves.
GitHub Pages. The gh-pages package is the deployment tool. The build script uses the --public-url ./ flag, and the deploy script pushes the dist directory to the gh-pages branch.
// package.json โ the GitHub Pages scripts
{
"scripts": {
"build": "parcel build src/index.html --public-url ./",
"deploy": "gh-pages -d dist"
}
}
The --public-url ./ is the flag that makes the subpath deployment work . The gh-pages -d dist command publishes the dist directory.
Complete Example Session
// ============================================
// PART 1: THE BUILD SCRIPT
// ============================================
// package.json
{
"source": "src/index.html",
"scripts": {
"build": "parcel build src/index.html"
},
"targets": {
"main": false
}
}
// The source field is the entry.
// The targets.main: false disables the main field inference.
// ============================================
// PART 2: THE SUBPATH BUILD
// ============================================
// package.json โ the GitHub Pages build
{
"scripts": {
"build": "parcel build src/index.html --public-url ./"
}
}
// The --public-url ./ flag produces relative paths.
// The assets resolve against the subpath.
// ============================================
// PART 3: THE NETLIFY CONFIG
// ============================================
// netlify.toml
[build]
command = "parcel build src/index.html"
publish = "dist"
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
// The publish is dist.
// The redirect is the SPA fallback.
// ============================================
// PART 4: THE VERCEL CONFIG
// ============================================
// vercel.json
{
"builds": [{
"src": "src/index.html",
"use": "@vercel/static-build",
"config": { "distDir": "dist" }
}],
"routes": [
{ "handle": "filesystem" },
{ "src": "/.*", "dest": "/index.html" }
]
}
// The distDir is dist.
// The routes are the SPA fallback.
// ============================================
// PART 5: THE GITHUB PAGES DEPLOY
// ============================================
// package.json
{
"scripts": {
"build": "parcel build src/index.html --public-url ./",
"deploy": "gh-pages -d dist"
}
}
// The build produces the relative-path bundle.
// The deploy pushes dist to the gh-pages branch.
// ============================================
// PART 6: THE PUBLIC URL PROBLEM
// ============================================
// A subpath deployment without --public-url ./:
// The asset paths are /index.hash.js.
// The browser requests the domain root, not the subpath.
// The page is blank.
// With --public-url ./:
// The asset paths are ./index.hash.js.
// The browser resolves against the subpath.
// The page loads.
// ============================================
// PART 7: THE PUBLISH DIRECTORY PROBLEM
// ============================================
// A host configured to serve the project root:
// The source index.html is served.
// The source index.html references the source files.
// The bundle is not loaded.
// The fix: set the publish directory to dist.
// ============================================
// PART 8: THE SPA REWRITE
// ============================================
// A request for /dashboard:
// The static host looks for a file.
// The file does not exist.
// The 404 is returned before the router runs.
// The rewrite rule serves index.html for the path.
// The router reads /dashboard and renders the route.
// ============================================
// PART 9: THE VERIFICATION
// ============================================
// 1. Run the build: npm run build
// 2. Inspect dist/: the index.html and the hashed assets
// 3. Deploy the dist/ directory to the host
// 4. Open the root URL
// 5. Navigate to a route and refresh
// 6. Check the network tab for the asset paths
// ============================================
// PART 10: THE CHECKLIST
// ============================================
// [ ] The build command is parcel build.
// [ ] The publish directory is dist.
// [ ] The main field inference is disabled.
// [ ] The --public-url ./ flag is used for a subpath deployment.
// [ ] The SPA rewrite rule is configured on the host.
// [ ] The asset paths resolve correctly after deployment.
The ten parts covered the build script, the subpath build, the Netlify config, the Vercel config, the GitHub Pages deploy, the public URL problem, the publish directory problem, the SPA rewrite, the verification, and the checklist. The through-line is that the build is the same and the host configuration is the variable.
Quick Reference
The build settings
| Setting | Value |
|---|---|
| Build command | parcel build src/index.html |
| Publish directory | dist |
| Subpath flag | --public-url ./ |
| Main inference disable | "targets": { "main": false } |
The host configurations
| Host | File | Publish setting | SPA rewrite |
|---|---|---|---|
| Netlify | netlify.toml | publish = "dist" | [[redirects]] |
| Vercel | vercel.json | distDir: "dist" | routes array |
| GitHub Pages | package.json | gh-pages -d dist | (not supported) |
The public URL
| Deployment | Flag | Asset path |
|---|---|---|
| Domain root | (none) | /index.hash.js |
| Subpath | --public-url ./ | ./index.hash.js |
Best Practices
โ Do This:
// Use the source field or pass the entry explicitly
"build": "parcel build src/index.html" // โ
# Use --public-url ./ for a subpath deployment
parcel build src/index.html --public-url ./ // โ
# Set the publish directory to dist
[build] publish = "dist" // โ
โ Don’t Do This:
# Deploy without the public URL for a subpath
parcel build src/index.html // assets point to the root // โ
// Leave the main field inference enabled
"main": "index.js" // Parcel treats the project as a library // โ
# Configure the host to serve the project root
# The source files are served, not the bundle. // โ
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Blank page on a subpath | The asset paths are absolute | Use --public-url ./ |
| The source files are served | The publish directory is the root | Set publish = "dist" |
| The build outputs to the wrong path | The main field is inferred | Set targets.main: false |
| A route returns a 404 on refresh | No SPA rewrite rule | Add the host-specific rewrite |
| The images are 404 | The public URL does not match the deployment | Set the correct --public-url |
Real-World Examples
1. The build command
"build": "parcel build src/index.html"
2. The subpath build
"build": "parcel build src/index.html --public-url ./"
3. The Netlify config
[build] publish = "dist"
[[redirects]] from = "/*" to = "/index.html" status = 200
4. The Vercel config
{ "builds": [{ "src": "src/index.html", "use": "@vercel/static-build", "config": { "distDir": "dist" } }] }
5. The GitHub Pages deploy
"deploy": "gh-pages -d dist"
6. The main field disable
"targets": { "main": false }
7. The source field
"source": "src/index.html"
8. The publish directory
dist
9. The public URL
--public-url ./
10. The verification
npm run build && ls dist/
Visual
The Deployment Flow
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ FROM SOURCE TO HOST โ
โ โ
โ src/index.html โ
โ โ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ parcel build โ Bundles, minifies, hashes โ
โ โโโโโโโโโโโโฌโโโโโโโโโโโ โ
โ โ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ dist/ โ The publish directory โ
โ โ index.html โ โ
โ โ index.hash.js โ โ
โ โ index.hash.css โ โ
โ โโโโโโโโโโโโฌโโโโโโโโโโโ โ
โ โ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Static host โ Serves dist/ โ
โ โ + rewrite rule โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The Public URL Problem
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ABSOLUTE VS RELATIVE PATHS โ
โ โ
โ Without --public-url ./: โ
โ /index.hash.js โ domain root โ
โ Subpath deployment โ 404 โ
โ โ
โ With --public-url ./: โ
โ ./index.hash.js โ current directory โ
โ Subpath deployment โ works โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The SPA Rewrite
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ THE REWRITE SERVES index.html FOR UNMATCHED PATHS โ
โ โ
โ Request /dashboard โ
โ โ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ The host checks โ โ
โ โ for a file โ โ
โ โโโโโโโโโโโโฌโโโโโโโโโโโ โ
โ โ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ No file โ serve โ โ
โ โ index.html โ โ
โ โโโโโโโโโโโโฌโโโโโโโโโโโ โ
โ โ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ The router reads โ โ
โ โ /dashboard โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| Item | Value |
|---|---|
| Build command | parcel build src/index.html |
| Publish directory | dist |
| Subpath flag | --public-url ./ |
| Main inference disable | "targets": { "main": false } |
| Netlify rewrite | [[redirects]] in netlify.toml |
| Vercel rewrite | routes in vercel.json |
| GitHub Pages deploy | gh-pages -d dist |
Key takeaways:
- The build is the same; the host configuration is the variable. Parcel writes the bundle to
dist, and the deployment is the process of serving that directory with the host-specific settings. The build command isparcel build, and the publish directory isdist. - The public URL is the subpath fix. A deployment at the domain root uses absolute paths. A deployment under a subpath needs
--public-url ./to produce relative paths. Without the flag, the assets point to the domain root and the page is blank . - The
mainfield inference is the output path trap. Parcel reads themainfield and treats the project as a library if the field is present. A web application should set"targets": { "main": false }or remove the field to ensure the output goes to the correct path . - The SPA needs a rewrite rule. A static host returns a 404 for a client-side route before the router can run. The rewrite rule serves
index.htmlfor unmatched paths, and the rule is host-specific:_redirectson Netlify,routeson Vercel,try_fileson Nginx . - The publish directory is the most common misconfiguration. A host that is configured to serve the project root instead of
distwill serve the source files, not the bundle. The fix is to set the publish directory todistin the host’s configuration.
Remember: A Parcel deployment is the dist directory plus the host configuration. The build command is parcel build, the publish directory is dist, and the public URL is the flag that makes a subpath deployment work. The main field inference is the trap that writes the output to the wrong path, and the SPA rewrite is the rule that makes client-side routing work on refresh. The build is the same; the host is the variable. The two settings that cause the most failures are the publish directory and the public URL.
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!