🐛 bug report
I’ve started trying to use Parcel2 in a real-life situation, and I’m noticed that the parcel bundle size (1.1MB) is significantly larger than webpack’s (666 KiB) for the same app. (It’s also significantly slower – see #4566).
Like all real-life situations, it’s complicated, so I tried to create a simplified repro environment in the fluentui-button-babel
branch of this repo. It’s a simple react app with a single Button
component from the @fluentui/react-northstar
library. This library is alpha-quality, and there’s known issues about bundle size that the team is trying to address. However, webpack still does a significantly better job than parcel right now. The main driver seems to be that this optimization that the library authors made is picked up by webpack but not by parcel.
🎛 Configuration (.babelrc, package.json, cli command)
Webpack (full config here):
- Using
babel-loader
with this config:
presets: [
"@babel/preset-env",
"@babel/preset-react",
"@babel/preset-typescript",
]
production
flag set totrue
, which enables minification throughTerserWebpackPlugin
and scope-hoisting/tree-shaking throughModuleConcatinationPlugin
, among other optimizations.
Parcel configuration:
- No
.parcelrc
file, which means that the default babel transformer is being used. - No custom babel configuration.
- Ran
parcel build src/index.html
src/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Sample App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="./index.tsx"></script>
</body>
</html>
src/index.tsx:
import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App";
ReactDOM.render(<App />, document.getElementById("root"));
src/components/App.ts:
import React from "react";
import { Provider, themes, Button } from "@fluentui/react-northstar";
const App = () => (
<Provider theme={themes.teams}>
<Button content="Hello from FluentUI" />
</Provider>
);
export default App;
🤔 Expected Behavior
Parcel and webpack build size should be roughly the same (or maybe Parcel should be better
😯 Current Behavior
Here’s the bundle size comparison:
Scenario | Bundle Size |
---|---|
Build with parcel (default babel config with scope-hoisting and minification) | 1.11 MB |
Build with webpack (babel-loader with scope-hoisting and minification) |
660 KiB |
Build with webpack (ts-loader with module: es6 with scope-hoisting and minification) |
660 KiB |
Build with webpack (ts-loader with module: commonjs with scope-hoisting and minification) |
1.21 MB |
💁 Possible Solution
By using source-map-explorer
and a custom node script, I generated a visualization of the stuff that is in the parcel bundle, but not the webpack bundle:
You can see that the main driver of the increased size are icons from the @fluentui/react-icons-northstar
. The fluentui team recently made an optimization to allow webpack to tree-shake these icons, and it seems that it works with webpack, but not with parcel.
I’m not sure why this is happening – most likely something at the scope-hoisting phase that doesn’t like the way this library was written. Even if there’s something the library authors could do to improve this, it seems like a good goal to do our best to make sure that libraries that are optimized for webpack remain optimized with parcel.
🔦 Context
Trying to build a real-world app that uses @fluentui/react-northstar
and parcel2.
💻 Code Sample
See the fluentui-button-babel
branch of this repo.
🌍 Your Environment
Software | Version(s) |
---|---|
Parcel | 2.0.0-nightly.248 |
Node | 12.16.3 |
Yarn | 1.22.4 |
Operating System | OSX 10.15.4 |
I have implemented the fix and the bundle size is 632kb compared to Webpack’s 635kb, will open a PR after more testing.
(But 600kb is still massive for a single Button)