Parcel 06 ๐ฆ Browserslist Targets โ Opting into transpilation
Parcel 2 does not transpile JavaScript by default. A project without a browserslist field in package.json produces output that assumes a modern browser, and Parcel does not run @babel/preset-env or its Rust-based equivalent unless it knows which browsers to target. The browserslist field is the opt-in: declaring it tells Parcel to transpile the syntax that the listed browsers do not support, and to add the CSS vendor prefixes that those browsers require .
This chapter covers the browserslist field, the query syntax that defines a target set, the default behavior when the field is absent, and the difference between the dev server’s modern target and the production build’s use of the declared list.
Key point: Parcel does not transpile unless browserslist is declared. The field is the switch that enables the transpilation pipeline, and its queries determine which syntax is downleveled and which prefixes are added.
Why Parcel requires an explicit target
The no-transpilation default. Parcel 2’s design is to do less work when it has no reason to do more. Without a browserslist, there is no target to compile for, so the output preserves the source syntax. A project that wants to support older browsers must declare that intent. The Stack Overflow answer states it directly: “Parcel 2 doesn’t do transpilation by default and you need to specify targeted browsers in the browserslist field of the package.json and then parcel automatically transpiles code with @babel/preset-env to match the defined target” .
The automatic transform problem. Once browserslist is present, Parcel enables its internal transforms. For JavaScript, it applies the Babel-equivalent transformations for the target syntax. For CSS, it includes equivalents of Autoprefixer and PostCSS Preset Env, implemented in Rust for speed. The documentation notes that if these are the only transforms the project needs, PostCSS may not be necessary at all .
The dev server distinction. The dev server uses a development target that supports modern browsers by default, which is why HMR stays fast. To make the dev server respect the browserslist field, the --target default flag must be passed . The production build (parcel build) uses the declared browserslist without the flag.
a. The browserslist field and query syntax
The field lives at the top level of package.json. It accepts a string or an array of strings, each of which is a Browserslist query.
{
"browserslist": [
"> 0.25%",
"not dead",
"not IE 11"
]
}
The queries are the standard Browserslist syntax. > 0.25% selects browsers with more than 0.25% global usage. last 2 Chrome versions selects the two most recent Chrome releases. not dead excludes browsers without official support for more than 24 months. The full query syntax is documented on browserslist.dev .
The default that many tutorials cite is > 0.25%, which Parcel historically used as its implicit target. With that default, the output covers roughly 92% of internet users at the time the tutorial was written . But the default is not a fallback that applies when the field is absent; it is the value that the field commonly contains.
b. What the field enables
Declaring browserslist turns on two independent pipelines.
The JavaScript pipeline. Parcel reads the queries and determines which syntax features the target browsers support. A feature that is unsupported is downleveled. The transformations are the same ones that @babel/preset-env would apply, but Parcel does not require the developer to install or configure @babel/preset-env. The Stack Overflow answer is explicit: “there is no need to add babel/preset-env and parcel/babel-preset-env manually. just remove them” .
The CSS pipeline. Parcel adds vendor prefixes for the target browsers and transpiles modern CSS syntax. The documentation states that Parcel “automatically handles CSS transpiling for modern syntax features like lab() colors, logical properties, and CSS nesting syntax, as well as automatically adding the necessary vendor prefixes for your browser targets” . This is the equivalent of Autoprefixer running automatically, without a PostCSS configuration.
c. Targets and the browserslist default
The browserslist field sets the default engines.browsers for the browser target. Parcel’s target configuration maps the browser target’s engines.browsers to package.json#browserslist unless the browser field exists . The main target’s engines.browsers is also populated from browserslist if there is no browser field .
A project with custom targets can override the browserslist default per target. The targets object in package.json accepts an engines field, and the browsers value inside it can be a different query set. The top-level browserslist is the default, not a global override.
{
"browserslist": ["> 0.25%", "not dead"],
"targets": {
"legacy": {
"engines": {
"browsers": ["IE 11"]
}
}
}
}
The legacy target compiles for IE 11. The default target compiles for the broader browserslist set. Parcel builds both from the same source.
Complete Example Session
// ============================================
// PART 1: THE MINIMAL BROWSERSLIST
// ============================================
{
"browserslist": ["> 0.25%", "not dead"]
}
// Parcel now transpiles JavaScript and CSS
// for the browsers matching these queries.
// ============================================
// PART 2: THE SPECIFIC QUERY SET
// ============================================
{
"browserslist": [
"last 2 Chrome versions",
"last 2 Firefox versions",
"last 2 Safari versions"
]
}
// The output targets only the most recent
// versions of the three major browsers.
// ============================================
// PART 3: THE ABSENT FIELD
// ============================================
{
"name": "my-app",
"dependencies": { "parcel": "^2.13.3" }
}
// No browserslist.
// No transpilation.
// The output uses the source syntax.
// ============================================
// PART 4: THE DEV SERVER FLAG
// ============================================
{
"scripts": {
"start": "parcel index.html --target default",
"build": "parcel build index.html"
}
}
// --target default makes the dev server
// respect the browserslist field.
// ============================================
// PART 5: THE PER-TARGET OVERRIDE
// ============================================
{
"browserslist": ["> 0.25%", "not dead"],
"targets": {
"legacy": {
"engines": {
"browsers": ["IE 11"]
}
}
}
}
// The default target uses the top-level list.
// The legacy target uses IE 11.
// ============================================
// PART 6: THE CSS PREFIX EXAMPLE
// ============================================
{
"browserslist": ["IE 9"]
}
// display: flex;
// becomes:
// display: -ms-flexbox;
// display: flex;
// ============================================
// PART 7: THE SYNTAX EXAMPLE
// ============================================
{
"browserslist": ["last 2 Chrome versions"]
}
// Optional chaining and nullish coalescing
// are preserved because Chrome supports them.
// ============================================
// PART 8: THE OLDER TARGET EXAMPLE
// ============================================
{
"browserslist": ["IE 11"]
}
// Optional chaining and nullish coalescing
// are downleveled into conditional checks.
// ============================================
// PART 9: THE AUTOPREFIXER EQUIVALENT
// ============================================
{
"browserslist": ["> 0.25%", "not dead"]
}
// Parcel adds the vendor prefixes that
// the target browsers require.
// No PostCSS configuration needed.
// ============================================
// PART 10: THE COMPLETE PACKAGE.JSON
// ============================================
{
"name": "my-app",
"browserslist": ["> 0.25%", "not dead"],
"scripts": {
"start": "parcel index.html --target default",
"build": "parcel build index.html"
},
"devDependencies": {
"parcel": "^2.13.3"
}
}
The ten parts covered the minimal field, a specific query set, the absent-field behavior, the dev server flag, the per-target override, CSS prefixing, syntax preservation, syntax downleveling, the Autoprefixer equivalent, and the complete package.json.
Quick Reference
Browserslist field
| Property | Detail |
|---|---|
| Location | Top level of package.json |
| Type | String or array of strings |
| Effect | Enables JS transpilation and CSS prefixing |
| Absent | No transpilation |
| Dev server | Uses modern target unless --target default |
Common queries
| Query | Meaning |
|---|---|
> 0.25% | Browsers with more than 0.25% usage |
last 2 versions | Two most recent versions of each browser |
last 2 Chrome versions | Two most recent Chrome releases |
not dead | Exclude browsers without official support |
IE 11 | Internet Explorer 11 |
defaults | Browserslist’s recommended default set |
Target configuration
| Field | Effect |
|---|---|
browserslist | Default engines.browsers for targets |
targets.<name>.engines.browsers | Per-target override |
--target default | Dev server uses the browserslist field |
What is enabled
| Pipeline | Behavior |
|---|---|
| JavaScript | Downlevel syntax for target browsers |
| CSS | Add vendor prefixes, transpile modern syntax |
| PostCSS | Not required for the built-in transforms |
Best Practices
โ Do This:
// Declare browserslist explicitly
"browserslist": ["> 0.25%", "not dead"] // โ
// Use --target default for the dev server
"start": "parcel index.html --target default" // โ
// Use a specific query set for a defined audience
"browserslist": ["last 2 Chrome versions"] // โ
โ Don’t Do This:
// Omit browserslist and expect transpilation
// No field means no transpilation // โ
// Install @babel/preset-env manually
// Parcel handles it when browserslist is present // โ
// Use the dev server without --target default
// The dev target ignores browserslist // โ
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
Output uses modern syntax despite browserslist | Dev server uses its own modern target | Use --target default for the dev server |
| Transpilation not happening | No browserslist field | Add the field to package.json |
@babel/preset-env conflict | Manually installed preset | Remove it; Parcel handles it |
| CSS prefixes missing | The field is present but the query excludes the browser | Verify the query matches the target browser |
| Build differs from dev | Dev target and build target differ | Use --target default in dev |
Real-World Examples
1. Broad audience
{ "browserslist": ["> 0.25%", "not dead"] }
2. Modern only
{ "browserslist": ["last 2 Chrome versions"] }
3. Legacy support
{ "browserslist": ["IE 11"] }
4. Dev server flag
{ "start": "parcel index.html --target default" }
5. Production build
{ "build": "parcel build index.html" }
6. Per-target override
{ "targets": { "legacy": { "engines": { "browsers": ["IE 11"] } } } }
7. CSS prefix target
{ "browserslist": ["IE 9"] }
8. Syntax preservation
{ "browserslist": ["last 2 Chrome versions"] }
9. Syntax downleveling
{ "browserslist": ["IE 11"] }
10. The full package
{
"browserslist": ["> 0.25%", "not dead"],
"scripts": {
"start": "parcel index.html --target default",
"build": "parcel build index.html"
}
}
Visual
The opt-in switch
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ NO BROWSERSLIST โ
โ โ
โ Source code โโโบ Parcel โโโบ Output โ
โ โ
โ No transpilation. โ
โ No prefixing. โ
โ The output matches the source syntax. โ
โ โ
โ WITH BROWSERSLIST โ
โ โ
โ Source code โโโบ Parcel โโโบ Transpile for targets โโโบ Output โ
โ โ
โ JavaScript syntax downleveled. โ
โ CSS vendor prefixes added. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The two pipelines
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ BROWSERSLIST โ
โ โ โ
โ โโโ JavaScript pipeline โ
โ โ โโโ syntax downleveling โ
โ โ โ
โ โโโ CSS pipeline โ
โ โโโ vendor prefixes โ
โ โโโ modern syntax transpilation โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Dev server vs build
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ DEV SERVER BUILD โ
โ โ
โ Default: modern target browserslist is used โ
โ Fast HMR Full transpilation โ
โ โ
โ --target default No flag needed โ
โ โ uses browserslist โ
โ โ slower, but matches build โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Target override
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ browserslist: ["> 0.25%", "not dead"] โ
โ โ โ
โ โโโ default target โโโบ broad audience โ
โ โ โ
โ โโโ legacy target โโโบ engines.browsers: ["IE 11"] โ
โ โโโ IE 11 output โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| Item | Value |
|---|---|
| Field | browserslist in package.json |
| Effect | Enables JS transpilation and CSS prefixing |
| Default | No transpilation without the field |
| Dev server | Uses modern target unless --target default |
| Build | Uses browserslist automatically |
| Query syntax | Standard Browserslist syntax |
| Per-target override | targets.<name>.engines.browsers |
| Manual Babel | Not required |
Key takeaways:
- Parcel does not transpile without
browserslist. The field is the opt-in switch. A project that omits it gets output in the source syntax, which may fail in older browsers . - The field enables both JavaScript and CSS pipelines. JavaScript syntax is downleveled for the target browsers, and CSS vendor prefixes are added automatically. The built-in transforms are the equivalents of
@babel/preset-envand Autoprefixer, implemented in Rust . - The dev server uses a modern target by default. To make the dev server respect the
browserslistfield, pass--target default. The production build uses the field without the flag . - Manual Babel configuration is unnecessary. Parcel handles the transpilation when the field is present. Installing
@babel/preset-envorparcel/babel-preset-envmanually is redundant and should be removed . - Per-target overrides are possible. The top-level
browserslistsets the default, and a specific target can declare a differentengines.browsersvalue. This allows a single project to build both a modern bundle and a legacy bundle . - The query syntax is standard Browserslist.
> 0.25%,last 2 versions,not dead, andIE 11are all valid queries. The full syntax is documented on browserslist.dev .
Remember: The browserslist field is the contract between the project and Parcel. It says “these are the browsers I support,” and Parcel does the work to make the code run in them. Without the field, Parcel does nothing. With the field, it transpiles JavaScript, prefixes CSS, and produces output that matches the declared audience. The dev server needs --target default to honor the field; the production build honors it by default.
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!