Skip to content

Commit ca02182

Browse files
committed
feat: added 10-code-splitting
1 parent 7a80d80 commit ca02182

15 files changed

Lines changed: 237 additions & 0 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
VITE_API_BASE=http://localhost:8080
2+
VITE_ENABLE_FEATURE_A=true
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# Code Splitting
2+
3+
In this example, we are going add TailwindCSS integration.
4+
5+
📌 We start from sample `09-tailwindcss`.
6+
7+
# Steps to build it
8+
9+
## Prerequisites
10+
11+
Install [Node.js and npm](https://nodejs.org/en/) (20.19.0 || >=22.12.0) if they are not already installed on your computer.
12+
13+
> ⚠ Verify that you are running at least latest Node LTS version and npm. You can check your current version by running `node -v` and `npm -v` in a terminal/console window. Older versions may produce errors.
14+
15+
## Steps
16+
17+
- We start from `09-tailwindcss`. Just copy the project and install:
18+
19+
```bash
20+
npm install
21+
```
22+
23+
- Let's run the project:
24+
25+
```bash
26+
npm start
27+
```
28+
29+
🔎 Navigate to [http://localhost:5173](http://localhost:5173).
30+
31+
Code splitting is a performance optimization technique in frontend development where the application's JavaScript is broken into smaller, separate chunks that can be loaded on demand, rather than all at once.
32+
33+
This means parts of the code are only loaded when needed (e.g. when a user navigates to a specific page or triggers a certain action), which reduces the initial bundle size, improves load times, and enhances user experience.
34+
35+
In this example we're going to use a module that is loaded on demand.
36+
37+
- Let's add _src/math.ts_ file.
38+
39+
_src/math.ts_
40+
41+
```ts
42+
const randomBetween = (min: number, max: number) =>
43+
Math.floor(Math.random() * (max - min + 1)) + min;
44+
45+
export const operate = (n: number): number => {
46+
const base = Math.min(n, randomBetween(0, 50));
47+
const multiplier = randomBetween(1, 15);
48+
return base + multiplier;
49+
};
50+
```
51+
52+
We're going to use the `operate` function to apply a math operation to our counter.
53+
54+
- Modify `src/hello.tsx` to import the module dynamically and apply the `operate` function the the `counter` state:
55+
56+
```diff
57+
}, []);
58+
59+
+ const applyOperation = async () => {
60+
+ const { operate } = await import("./math");
61+
+ setCounter((prevCounter) => operate(prevCounter));
62+
+ };
63+
64+
return (
65+
<>
66+
<h2>Hello from React</h2>
67+
<p>Api server is {config.API_BASE}</p>
68+
<p>Feature A is {config.IS_FEATURE_A_ENABLED ? "enabled" : "disabled"}</p>
69+
<p>Counter state: {counter}</p>
70+
+ <button
71+
+ className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
72+
+ onClick={applyOperation}
73+
+ >
74+
+ Apply operation
75+
+ </button>
76+
<a
77+
href="#"
78+
className="m-2 block max-w-sm p-6 bg-white border border-gray-200 rounded-lg shadow-sm hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-700"
79+
>
80+
```
81+
82+
Notice we imported the `math` module dynamically using `import()` syntax. Vite will extract this module into its own bundle and will rely on native `import()` to download it at the time the button is clicked. Even if the user clicks multiple times on the button the module will be downloaded once.
83+
84+
Try yourself by clicking the button!
85+
86+
- Perform a build using `npm run build`:
87+
88+
```bash
89+
npm run build
90+
```
91+
92+
Notice two JavaScript files has been created under `dist/assets`: `index-[hash].js` and `math-[hash].js`.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html lang="en" data-theme="dark">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Vite App</title>
7+
</head>
8+
<body>
9+
<div id="root"></div>
10+
<script type="module" src="/src/index.tsx"></script>
11+
</body>
12+
</html>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "hello-vite",
3+
"private": true,
4+
"type": "module",
5+
"version": "0.0.0",
6+
"description": "Let's start with a very basic sample, just add an html plus a simple console log (E5). This is what you can find in the getting started tutorial.",
7+
"scripts": {
8+
"start": "vite --host",
9+
"build": "vite build",
10+
"preview": "vite preview"
11+
},
12+
"devDependencies": {
13+
"@tailwindcss/vite": "^4.1.11",
14+
"@types/react": "^19.1.8",
15+
"@types/react-dom": "^19.1.6",
16+
"@vitejs/plugin-react": "^4.6.0",
17+
"sass-embedded": "^1.89.2",
18+
"tailwindcss": "^4.1.11",
19+
"typescript": "^5.8.3",
20+
"vite": "^7.0.4",
21+
"vite-plugin-checker": "^0.10.0"
22+
},
23+
"dependencies": {
24+
"bootstrap": "^5.3.7",
25+
"react": "^19.1.0",
26+
"react-dom": "^19.1.0"
27+
}
28+
}
21.9 KB
Loading
14.2 KB
Loading
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const config = {
2+
API_BASE: import.meta.env.VITE_API_BASE,
3+
IS_FEATURE_A_ENABLED: import.meta.env.VITE_ENABLE_FEATURE_A === "true",
4+
} as const;
5+
6+
export default config;

03-bundling/06-vite/10-code-splitting/src/hello.module.css

Whitespace-only changes.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { FC, useEffect, useState } from "react";
2+
import config from "./env-config";
3+
4+
export const HelloComponent: FC = () => {
5+
const [counter, setCounter] = useState(0);
6+
7+
useEffect(() => {
8+
const timer = setInterval(() => {
9+
setCounter((prev) => prev + 1);
10+
}, 1_000);
11+
12+
return () => clearInterval(timer);
13+
}, []);
14+
15+
const applyOperation = async () => {
16+
const { operate } = await import("./math");
17+
setCounter((prevCounter) => operate(prevCounter));
18+
};
19+
20+
return (
21+
<>
22+
<h2>Hello from React</h2>
23+
<p>Api server is {config.API_BASE}</p>
24+
<p>Feature A is {config.IS_FEATURE_A_ENABLED ? "enabled" : "disabled"}</p>
25+
<p>Counter state: {counter}</p>
26+
<button
27+
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
28+
onClick={applyOperation}
29+
>
30+
Apply operation
31+
</button>
32+
<a
33+
href="#"
34+
className="m-2 block max-w-sm p-6 bg-white border border-gray-200 rounded-lg shadow-sm hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-700"
35+
>
36+
<h5 className="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">
37+
Card title
38+
</h5>
39+
<p className="font-normal text-gray-700 dark:text-gray-400">
40+
Some quick example text to build on the card title and make up the
41+
bulk of the card's content.
42+
</p>
43+
</a>
44+
</>
45+
);
46+
};
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { createRoot } from "react-dom/client";
2+
import { HelloComponent } from "./hello";
3+
import "./styles.css";
4+
5+
const root = createRoot(document.getElementById("root"));
6+
7+
root.render(<HelloComponent />);

0 commit comments

Comments
 (0)