You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -312,6 +313,187 @@ After this optimization, other optimizations can still apply. For example: `butt
312
313
313
314
Module Concatenation also applies. So that these 4 modules plus the entry module (and probably more dependencies) can be concatenated. **`index.js` has no code generated in the end**.
314
315
316
+
## Full Example: Understanding Side Effects with CSS Files
317
+
318
+
To better understand the impact of the `sideEffects` flag, let's look at a complete example of an npm package with CSS assets and how they might be affected during tree shaking. We'll create a fictional UI component library called "awesome-ui".
319
+
320
+
### Package Structure
321
+
322
+
Our example package looks like this:
323
+
324
+
```bash
325
+
awesome-ui/
326
+
├── package.json
327
+
├── dist/
328
+
│ ├── index.js
329
+
│ ├── components/
330
+
│ │ ├── index.js
331
+
│ │ ├── Button/
332
+
│ │ │ ├── index.js
333
+
│ │ │ └── Button.css
334
+
│ │ ├── Card/
335
+
│ │ │ ├── index.js
336
+
│ │ │ └── Card.css
337
+
│ │ └── Modal/
338
+
│ │ ├── index.js
339
+
│ │ └── Modal.css
340
+
│ └── theme/
341
+
│ ├── index.js
342
+
│ └── defaultTheme.css
343
+
```
344
+
345
+
### Package Files Content
346
+
347
+
**package.json**
348
+
349
+
```json
350
+
{
351
+
"name": "awesome-ui",
352
+
"version": "1.0.0",
353
+
"main": "dist/index.js",
354
+
"sideEffects": false
355
+
}
356
+
```
357
+
358
+
**dist/index.js**
359
+
360
+
```javascript
361
+
export*from'./components';
362
+
export*from'./theme';
363
+
```
364
+
365
+
**dist/components/index.js**
366
+
367
+
```javascript
368
+
export { defaultasButton } from'./Button';
369
+
export { defaultasCard } from'./Card';
370
+
export { defaultasModal } from'./Modal';
371
+
```
372
+
373
+
**dist/components/Button/index.js**
374
+
375
+
```javascript
376
+
import'./Button.css'; // This has a side effect - it applies styles when imported!
377
+
378
+
exportdefaultfunctionButton(props) {
379
+
// Button component implementation
380
+
return {
381
+
type:'button',
382
+
...props,
383
+
};
384
+
}
385
+
```
386
+
387
+
**dist/components/Button/Button.css**
388
+
389
+
```css
390
+
.awesome-ui-button {
391
+
background-color: #0078d7;
392
+
color: white;
393
+
padding: 8px16px;
394
+
border-radius: 4px;
395
+
border: none;
396
+
cursor: pointer;
397
+
}
398
+
```
399
+
400
+
**dist/components/Card/index.js** and **dist/components/Modal/index.js** would have similar structure.
401
+
402
+
**dist/theme/index.js**
403
+
404
+
```javascript
405
+
import'./defaultTheme.css'; // This has a side effect!
406
+
407
+
exportconstthemeColors= {
408
+
primary:'#0078d7',
409
+
secondary:'#f3f2f1',
410
+
danger:'#d13438',
411
+
};
412
+
```
413
+
414
+
### What Happens When Consuming This Package?
415
+
416
+
Now, imagine a consumer application that only wants to use the Button component:
417
+
418
+
```javascript
419
+
import { Button } from'awesome-ui';
420
+
421
+
// Use the Button component
422
+
```
423
+
424
+
#### With `sideEffects: false` in package.json
425
+
426
+
When webpack processes this import with tree shaking enabled:
427
+
428
+
1. It sees the import for only Button
429
+
2. It looks at the package.json and sees `sideEffects: false`
430
+
3. It determines it only needs to include the Button component code
431
+
4. Since all files are marked as having no side effects, it will include **only** the JavaScript code for the Button
432
+
5.**The CSS file import gets dropped!** Even though Button.css is imported in Button/index.js, webpack assumes this import has no side effects.
433
+
434
+
The result: The Button component will render, but without any styling since Button.css was eliminated during tree shaking.
435
+
436
+
#### The Correct Configuration for This Package
437
+
438
+
To fix this, we need to update package.json to properly mark CSS files as having side effects:
439
+
440
+
```json
441
+
{
442
+
"name": "awesome-ui",
443
+
"version": "1.0.0",
444
+
"main": "dist/index.js",
445
+
"sideEffects": ["**/*.css"]
446
+
}
447
+
```
448
+
449
+
With this configuration:
450
+
451
+
1. Webpack still identifies that only the Button component is needed
452
+
2. But now it recognizes that CSS files have side effects
453
+
3. So, it includes Button.css when processing Button/index.js
454
+
455
+
### The Decision Tree for Side Effects
456
+
457
+
Here's how webpack evaluates modules during tree shaking:
458
+
459
+
1. Is the export from this module used directly or indirectly?
460
+
461
+
- If yes: Include the module
462
+
- If no: Continue to step 2
463
+
464
+
2. Is the module marked with side effects?
465
+
- If yes (`sideEffects` includes this file or is `true`): Include the module
466
+
- If no (`sideEffects` is `false` or doesn't include this file): Exclude the module and its dependencies
467
+
468
+
For our library's files with the proper sideEffects configuration:
469
+
470
+
-`dist/index.js`: No direct export used, no side effects -> Skip over
471
+
-`dist/components/index.js`: No direct export used, no side effects -> Skip over
472
+
-`dist/components/Button/index.js`: Direct export used -> Include
473
+
-`dist/components/Button/Button.css`: No exports, has side effects -> Include
474
+
-`dist/components/Card/*`: No exports used, no side effects -> Exclude
475
+
-`dist/components/Modal/*`: No exports used, no side effects -> Exclude
476
+
-`dist/theme/*`: No exports used, no side effects -> Exclude
477
+
478
+
### Real-World Impact
479
+
480
+
The impact of incorrect side effects configuration can be significant:
481
+
482
+
1.**CSS not being included**: Components render without styles
483
+
2.**Global JavaScript not running**: Polyfills or global configurations don't execute
484
+
3.**Initialization code skipped**: Functions that register components or set up event listeners never run
485
+
486
+
These issues can be particularly hard to debug because they often only appear in production builds when tree shaking is enabled.
487
+
488
+
### Testing Side Effects Configuration
489
+
490
+
A good way to test if your side effects configuration is correct:
491
+
492
+
1. Create a minimal application that imports just one component
493
+
2. Build it with production settings (with tree shaking enabled)
494
+
3. Check if all necessary styles and behaviors work correctly
495
+
4. Look at the generated bundle to confirm the right files are included
496
+
315
497
## Mark a function call as side-effect-free
316
498
317
499
It is possible to tell webpack that a function call is side-effect-free (pure) by using the `/*#__PURE__*/` annotation. It can be put in front of function calls to mark them as side-effect-free. Arguments passed to the function are not being marked by the annotation and may need to be marked individually. When the initial value in a variable declaration of an unused variable is considered as side-effect-free (pure), it is getting marked as dead code, not executed and dropped by the minimizer.
@@ -354,13 +536,49 @@ Notice anything different about `dist/bundle.js`? The whole bundle is now minifi
354
536
355
537
T> [`ModuleConcatenationPlugin`](/plugins/module-concatenation-plugin/) is needed for the tree shaking to work. It is added by `mode: 'production'`. If you are not using it, remember to add the [`ModuleConcatenationPlugin`](/plugins/module-concatenation-plugin/) manually.
356
538
539
+
## Common Pitfalls with Side Effects
540
+
541
+
When working with tree shaking and the `sideEffects` flag, there are several common pitfalls to avoid:
542
+
543
+
### 1. Over-optimistic `sideEffects: false`
544
+
545
+
Setting `sideEffects: false` in your package.json is tempting for optimal tree shaking, but this can cause problems if your code actually does have side effects. Examples of hidden side effects:
546
+
547
+
- CSS imports (as demonstrated above)
548
+
- Polyfills that modify global objects
549
+
- Libraries that register global event listeners
550
+
- Code that modifies prototype chains
551
+
552
+
### 2. Re-exports with Side Effects
553
+
554
+
Consider this pattern:
555
+
556
+
```javascript
557
+
// This file has side effects that might be skipped
558
+
import'./polyfill';
559
+
560
+
// Re-export components
561
+
export*from'./components';
562
+
```
563
+
564
+
If a consumer only imports specific components, the polyfill import might be skipped entirely if not properly marked with side effects.
565
+
566
+
### 3. Forgetting about Nested Dependencies
567
+
568
+
Your package might correctly mark side effects, but if it depends on third-party packages that incorrectly mark their side effects, you might still encounter issues.
569
+
570
+
### 4. Testing Only in Development Mode
571
+
572
+
Tree shaking typically only fully activates in production mode. Testing only in development can hide tree shaking issues until deployment.
573
+
357
574
## Conclusion
358
575
359
576
What we've learned is that in order to take advantage of _tree shaking_, you must...
360
577
361
578
- Use ES2015 module syntax (i.e. `import` and `export`).
362
579
- Ensure no compilers transform your ES2015 module syntax into CommonJS modules (this is the default behavior of the popular Babel preset @babel/preset-env - see the [documentation](https://babeljs.io/docs/en/babel-preset-env#modules) for more details).
363
580
- Add a `"sideEffects"` property to your project's `package.json` file.
581
+
- Be careful about correctly marking files with side effects, especially CSS imports.
364
582
- Use the [`production`](/configuration/mode/#mode-production)`mode` configuration option to enable [various optimizations](/configuration/mode/#usage) including minification and tree shaking (side effects optimization is enabled in development mode using the flag value).
365
583
- Make sure you set a correct value for [`devtool`](/configuration/devtool/#devtool) as some of them can't be used in `production` mode.
0 commit comments