# NPM 安裝以及 React Project 演練
> 目標:帶你從 **安裝 Node.js/npm** → **理解 ES Module(import/export)** → **建立 React 專案** → **切分組件與加入樣式**。同時提供 **Vite(推薦)** 與 **Create React App(舊方案)** 兩條路線,以及常見安裝錯誤排除。
---
## 一、從安裝 Node.js 開始
**Node.js** 是瀏覽器外的 JavaScript 執行環境,常見於後端(如 Express)與建置工具(打包、測試、Lint 等)。安裝 Node 時會附帶 **npm(Node Package Manager)**,用來安裝/管理套件與執行專案腳本。
### 1. 安裝 Node.js(建議 LTS 版本)
* 前往官方網站下載安裝程式:[https://nodejs.org](https://nodejs.org)
* 安裝完成後在終端機驗證:
```bash
node -v # 顯示 Node 版本
npm -v # 顯示 npm 版本
```
### 2. 版本管理(選用,但強烈建議)
不同專案可能需要不同 Node 版本,建議安裝版本管理器:
* macOS/Linux:`nvm` 或 `fnm`
* Windows:`nvm-windows` 或 `fnm`
有了版本管理器後,可以輕鬆切換:
```bash
nvm install --lts
nvm use --lts
```
> 有 `yarn`、`pnpm` 等替代方案;本講義以 **npm** 為主,指令可類推。
<br/>
## 二、JavaScript 的 `import` 與 `export`
ES Module 讓程式可模組化、可重用、好維護。
### Export(導出)
**命名導出**:
```js
export const A = 1;
export function greet(name) { return `Hi, ${name}`; }
```
**預設導出**(一個模組僅一個 default):
```js
const PI = 3.14159;
export default PI;
```
### Import(導入)
**命名導入**:
```js
import { A, greet } from './utils.js';
```
**預設導入**:
```js
import PI from './constants.js';
```
**整包導入**:
```js
import * as math from './math.js';
```
> 注意:ESM 天生嚴格模式;導入值為唯讀(但若為物件其內容仍可變動)。
<br/>
## 三、建立並啟動 React 專案
> 2025 年的實務建議:**優先用 Vite 或 Next.js**;`create-react-app`(CRA)已停更多年,仍可用於學習,但不建議新專案採用。
### 路線 A:使用 Vite(推薦)
1. 建立專案:
```bash
npm create vite@latest my-react-app -- --template react
cd my-react-app
npm install
npm run dev
```
2. 重要檔案結構:
```
my-react-app/
├─ index.html
├─ package.json
├─ vite.config.ts (或 .js)
└─ src/
├─ App.jsx
└─ main.jsx
```
3. 入口檔(Vite 預設):
```jsx
// src/main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>
)
```
```jsx
// src/App.jsx
export default function App() {
return <div>Hello React (Vite)</div>
}
```
### 路線 B:Create React App(教學/舊方案)
```bash
npx create-react-app my-app
cd my-app
npm start
```
**CRA 典型結構**:
```
my-app/
├─ public/index.html
├─ src/index.js
├─ src/App.js
└─ package.json
```
**React 18 匯入要點**:React 18 之後需從 `react-dom/client` 匯入 `createRoot`:
```jsx
// src/index.js (React 18 正確寫法)
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
)
```
> 你原文提到「不需要加 /client」是 **React 17 舊寫法**。若使用 React 18,請務必用 `react-dom/client`。
<br/>
## 四、最少檔案的 React 專案(以 CRA 流程示意)
> 目標:用最少檔案跑起來,理解每個檔案的責任。
**檔案結構**
```
- src
index.js
- public
index.html
package.json
```
**package.json(CRA 範例)**
```json
{
"name": "my-react-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-scripts": "5.0.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
```
**public/index.html**
```html
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>React App</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
```
**src/index.js**
```jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
<React.StrictMode>
<div>Hello React</div>
</React.StrictMode>
)
```
[程式範本](https://github.com/IffyArt/2025-fullstack-course-forntend/tree/feature/react-basic-project)
<br/>
## 五、把 `App.js` 獨立並渲染到首頁
**目錄**
```
- src
App.js
index.js
- public
index.html
```
**src/App.js**
```jsx
export default function App() {
return <div>Hello React, I am App.js</div>
}
```
**src/index.js(React 18)**
```jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
)
```
> 分檔的目的:`index.js` 專注「掛載/啟動」,`App.js` 專注「畫面與邏輯」。可讀性與維護性更好。
<br/>
## 六、切分元件(Components)
**目錄**
```
- src
- components
Header.jsx
App.js
index.js
```
**src/components/Header.jsx**
```jsx
const Header = () => (
<header>
<h1>Welcome to My Website</h1>
</header>
)
export default Header
```
**src/App.js**
```jsx
import Header from './components/Header'
export default function App() {
return (
<>
<Header />
Hello React, I am App.js
</>
)
}
```
> `<>...</>` 是 `React.Fragment` 的語法糖:不多包一層多餘的 `<div>`。
<br/>
## 七、加入樣式(CSS / 外部資源)
**目錄**
```
- src
- components
Header.jsx
- styles
style.css
App.js
index.js
```
**src/styles/style.css**
```css
.header {
background-color: #333;
color: white;
padding: 1rem;
text-align: center;
height: 200px;
}
```
**src/components/Header.jsx**
```jsx
const Header = () => (
<header className="header">
<h1>Welcome to My Website</h1>
</header>
)
export default Header
```
**src/App.js**
```jsx
import Header from './components/Header'
import './styles/style.css'
export default function App() {
return (
<div>
<Header />
Hello React, I am App.js
</div>
)
}
```
> 在 JSX 內用 **`className`** 取代 `class`。
### 外部資源(以 Bootstrap、Google Icons 為例)
在 `public/index.html` 直接引入最快:
```html
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
```
範例(`App.js`)
```jsx
import Header from './components/Header'
import './styles/style.css'
export default function App() {
return (
<div>
<Header />
<div className="btn-group" role="group" aria-label="Basic mixed styles example">
<span className="material-symbols-outlined">logout</span>
<button type="button" className="btn btn-danger">Left</button>
<button type="button" className="btn btn-warning">Middle</button>
<button type="button" className="btn btn-success">Right</button>
</div>
</div>
)
}
```
<br/>
## 八、常見安裝/啟動錯誤排除
### 1) Windows 執行 `npx` 出現找不到 Roaming/npm 目錄
```text
npm ERR! enoent ENOENT: no such file or directory, lstat 'C:\\Users\\User\\AppData\\Roaming\\npm'
```
**解法**(以 CMD):
```bat
mkdir %USERPROFILE%\AppData\Roaming\npm
```
### 2) 連不上 Registry / 權限問題
* 確認網路與代理;或切換 registry:
```bash
npm config set registry https://registry.npmmirror.com
# 或
npm config set registry https://registry.npmjs.org
```
* 權限錯誤請避免用系統管理員身分安裝全域套件;或改用版本管理器。
### 3) React 版本對應 `react-dom` 匯入
* **React 18**:`import ReactDOM from 'react-dom/client'` + `createRoot(...)`
* **React 17**(舊):`import ReactDOM from 'react-dom'` + `ReactDOM.render(...)`