# 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(...)`