# JS 的奇幻旅程 <br>
## 套件管理工具、Module Bundler
[TOC]
----
Made by FanRende (030Mortal#5525)
<img src="https://i.imgur.com/jbmRCOw.png" width="25%">
---
## 套件是什麼?
> 不要重複造輪子
使用別人公開的程式碼作為開發的一部分
----
### 套件管理工具
Javascript 廣為使用的有兩個工具 `npm`、`yarn`
在這邊我會使用 `npm` 來做範例 <span class="gray">(因為我沒用過 `yarn`)</span>
----
### Node Package Manager
<div class="flex-container">
<div class="flex-content">
```json
// package.json
{
"name": "my-vite-app",
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.9",
"@vitejs/plugin-react": "^3.0.0",
"typescript": "^4.9.3",
"vite": "^4.0.0"
}
}
```
</div>
<div class="flex-content">
```json
// package.lock.json
{
"name": "my-vite-app",
"version": "0.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "my-vite-app",
"version": "0.0.0",
"dependencies": {
"@types/node": "^18.11.18",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.9",
"@vitejs/plugin-react": "^3.0.0",
"typescript": "^4.9.3",
"vite": "^4.0.0"
}
},
"node_modules/@ampproject/remapping": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/...",
"integrity": "sha512-...",
"dev": true,
"dependencies": {
"@jridgewell/gen-mapping": "^0.1.0",
"@jridgewell/trace-mapping": "^0.3.9"
},
"engines": {
"node": ">=6.0.0"
}
}
},
"dependencies": {
"@ampproject/remapping": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/...",
"integrity": "sha512-...",
"dev": true,
"requires": {
"@jridgewell/gen-mapping": "^0.1.0",
"@jridgewell/trace-mapping": "^0.3.9"
}
},
"@babel/code-frame": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/...",
"integrity": "sha512-...",
"dev": true,
"requires": {
"@babel/highlight": "^7.18.6"
}
}
}
}
```
</div>
</div>
----
#### npm 指令
- `npm install`
- 安裝該目錄下 package.json / package.lock.json 中的套件
- `npm install <package>`
- 安裝指定套件
- `npm run <script>`
- 執行 package.json 中的 script
----
### Node Package Executor
如果想要執行一個 package 可以使用 `npx`
可以不需要在全域安裝該 package
e.g. `npx create-react-app my-app`
---
## Module Bundler
將前端開發工程化
可以將各個部件模組化後利用 webpack 等工具整合
----
### webpack
- Entry (`./src/index.js`)
- Output (`/dist/main.js`)
- Loaders
- 除了 html, js, css 外的檔案需要用 loader
- sass: sass-loader
- Plugins
- Mode
- production
- development
- Browser Compatibility
----
#### Tree shaking
把模組相依樹搖一搖 看哪些模組沒用到就搖下來
為了實現這個功能需要靜態分析程式碼
----
#### Dynamic import
載入使用者當前頁面需要的檔案就好
#### Dead Code elimination
```javascript
if (false) {
console.log("out")
}
```
#### Code Splitting
可以將第三方程式碼利用 cdn 進行快取
#### Minify
變數命名、code style minify
----
#### Hot Module Replacement
另外啟動一個 server 監聽檔案變化
```mermaid
graph TD;
class init initial;
classDef red stroke:#f66,stroke-width:4px;
index((index))
ma((moduleA))
mb((moduleB))
mc((moduleC))
md((moduleD))
me((moduleE))
class mc red;
class me red;
index ---> ma;
index ---> mb;
ma ---> mc;
ma ---> md;
mb ---> me;
```
----
### Vite
法語中的**快** ,是念 Vite 不是 Vite(?)
由於它不會在 build 時編譯所有檔案 而是需要時才 load 進來 因此速度相較 webpack 快非常多
而他的 HSM 利用了 webSocket/Chokidar/esbuild 技術也會讓他的即時熱更新比 webpack 快
----
#### React with Vite
- CRA
- `npx create-react-app my-app`
- Vite
- `npm create vite@latest`
- `npm create vite@latest my-app --template react`
- `npm create vite@latest my-app -- --template react`
---
## Babel
將 Javascript 先轉換成抽象語法樹,再用各種 plugin 來轉換對應的程式碼
----
### Abstract Syntax Tree 抽象語法樹
<div class="flex-container">
<div class="flex-content">
```json
{
"type": "Program",
"start": 0,
"end": 40,
"body": [
{
"type": "ExpressionStatement",
"start": 0,
"end": 27,
"expression": {
"type": "CallExpression",
"start": 0,
"end": 26,
"callee": {
"type": "MemberExpression",
"start": 0,
"end": 11,
"object": {
"type": "Identifier",
"start": 0,
"end": 7,
"name": "console"
},
"property": {
"type": "Identifier",
"start": 8,
"end": 11,
"name": "log"
},
"computed": false
},
"arguments": [
{
"type": "Literal",
"start": 12,
"end": 25,
"value": "hello world",
"raw": "'hello world'"
}
]
}
}
}
```
</div>
<div class="flex-content">
`console.log('hello world')`
`console` -> CallExpression
`log` -> MemberExpression
`hello world` -> Literal
</div>
</div>
----
### jsx
<div class="flex-container">
<div class="flex-content">
```javascript
function MyComponent() {
return React.createElement("div", null,
React.createElement("span", null,
"hello world"
));
}
// 等價於
function MyComponent() {
return <div>
<span>hello world</span>
</div>
}
```
</div>
<div class="flex-content">
透過 babel plugin 將 jsx 與 React.createElement 相互轉換
</div>
</div>
---
參考 / 延伸閱讀:
[為什麼前端需要工程化? — webpack](https://f2e.kalan.dev/frontend-engineering/8.html)
[Babel 簡介](https://f2e.kalan.dev/frontend-engineering/9.html)
[前端技能樹的十萬個為什麼](https://ithelp.ithome.com.tw/users/20141641/ironman/5767)
<!-- <span style="margin-left: 50vw"></span> -->
<style>
.gray {
color: gray;
font-size: 0.5em;
}
.json {
font-size: 0.5em !important;
line-height: 1.5em !important;
}
.mermaid {
background-color: #fcf8eb !important;
}
.flex-container {
display: flex;
justify-content: center;
}
.flex-content {
flex-grow: 1;
}
</style>
<style>
/* Customize website's scrollbar like Mac OS
Not supports in Firefox and IE */
/* total width */
body::-webkit-scrollbar {
background-color: #fff;
width: 16px;
}
/* background of the scrollbar except button or resizer */
body::-webkit-scrollbar-track {
background-color: #fff;
}
/* scrollbar itself */
body::-webkit-scrollbar-thumb {
background-color: #babac0;
border-radius: 16px;
border: 4px solid #fff;
}
/* set button(top and bottom of the scrollbar) */
body::-webkit-scrollbar-button {
display:none;
}
</style>
{"metaMigratedAt":"2023-06-17T19:04:58.450Z","metaMigratedFrom":"YAML","title":"JS 的奇幻旅程 套件管理工具、Module Bundler","breaks":true,"description":"簡介套件管理工具及 Module Bundler","slideOptions":"{\"theme\":\"solarized\",\"transition\":\"fade\",\"previewLinks\":true}","contributors":"[{\"id\":\"82f6b599-31b8-4112-9dc5-7d7b7d6a3ebb\",\"add\":10447,\"del\":3388}]"}