基本上瀏覽器只看得懂三種語言,分別是 HTM、CSS 和 JavaScript,因此接下來學習 React 使用的 JSX 語法,瀏覽器無法讀懂,也沒辦法執行正確的結果給我們,因此我們需要 Babel 幫忙,它會依照語法規則將程式碼翻譯給瀏覽器看。
但 Babel 處理的也不全然是 JavaScript 外的語法,有些新版本的 JavaScript 瀏覽器開放支援前也會看不懂,這時候 Babel 也能將這些新版本的語法翻譯成舊的版本,讓大部分的網頁能夠正確執行。
注意!
如果 ESLint 沒有反應,要再用以下指令另外下載 @babel/runtime:
npm install @babel/runtime --save-dev
他是 Day02 的 eslint-config-airbnb 依賴套件,雖然 Day02 很正常,但複製到 Day03 就出現找不到這個套件的錯誤,我不確定是不是大家都會有這個狀況,如果是的話麻煩留言告訴我,我會直接將該套件補到 Day02 的 Package.json 裡。
在開始前,先將 src/index.js 打開,並將內容改為下方:
for (let i = 0; i <= 10; i += 1) {
console.log(i);
}
完成後透過 npm run build
讓 Webpack 將它打包,並打開打包後的 dist/bundle.js:
會發現在宣告時,依舊是用 let
,也就是說
這也是 Webpack 的基本工作,但並不是所有的瀏覽器版本都能夠正確支援 let
,於是為了能使用這些好用的新版本 JavaScript 語法,就得搭配使用 Babel 替程式做翻譯。
因為目前還沒在專案裡裝上 React,因此本階段的首要目標,先讓 ES6
的語法能正確被轉換。
開啟專案後,輸入以下指令安裝 Babel 的核心套件:
npm install @babel/core @babel/cli --save-dev
不同的編譯對象會有不同的 Preset,它會觀察程式裡有哪些地方需要做處理語法轉換,因此下載對 ES6
轉換語法的 Preset:
npm install @babel/preset-env --save-dev
Babel 會有個設定檔 babel.config.js,但目前暫時不需要也沒關係,因為 Webpack 在編譯時能夠設定 loader 使用 Babel,因此先下載 Webpack 需要的 loader 套件:
npm install babel-loader --save-dev
下載完後,到 webpack.config.js 中的 module
中設置轉換規則:
const path = require('path');
module.exports = {
/* 其餘省略 */
module: {
rules: [
{
test: /.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
],
},
};
關於上方的設置內容,有幾個比較需要了解:
rules
:之後如果有新要轉換語法的地方,都會在這邊設置,包括 Sass 轉換成 css 也是。test
:這裡是目標檔案的副檔名,上方用正規表達式處理,讓所有 .js 結尾的都經由這個 rules
的 loader 做轉換。presets
: 針對不同的副檔名(例如:JSX)會有不同的 Preset,而同一種副檔名也能夠使用多個 Preset。接著使用 npm run build
再做一次編譯,就會看到他已經成為大部分瀏覽器都支援的可愛模樣:
今天再請大家陪我久一點,接下來要下載 React,透過 Babel 從 JSX 轉換成一般的 JS:
npm install react --save
npm install react-dom --save
下載好後,打開 src/index.js,將檔名改成 index.jsx,並在裡面輸入:
import React from 'react';
import ReactDom from 'react-dom';
const Main = () => <h1>Hi JSX!</h1>;
ReactDom.render(<Main />, document.getElementById('root'));
上方這裡先複製貼上,React 的使用方式會在後天開始一一為大家說明,今天的目的要能正確編譯 JSX 到 JavaScript。
接下來要下載負責編譯 JSX 語法的 Preset:
npm install @babel/preset-react --save-dev
載好後,再回到 webpack.config.js 身上,加入對 jsx
的 loader,也不要忘了將 entry
的檔案從原本的 index.js 改成 index.jsx:
entry: './src/index.jsx',
module: {
rules: [
/* 其餘省略 */
{
test: /.jsx$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-react', '@babel/preset-env'],
},
},
},
],
}
這裡的 Preset 配置了兩個,因為 @babel/preset-react
只負責轉換 JSX 的語法,並不會幫忙處理 ES6 的部分,所以另外加上 @babel/preset-env
將 JavaScript 轉換成通用的版本,沒問題的話就能編譯看看:
最後,既然已經打包完 JavaScript 了,何不看看呈現的結果呢?
到 dist 的目錄下新增一個 index.html,並在裡面貼上下方的內容:
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="root"></div>
<script src="./bundle.js"></script>
</body>
</html>
再來將 dist/index.html 用瀏覽器打開,就能看到精美的「Hi JSX!」:
最後來看看 Babel 到底對 JSX 做了什麼,打開 dist/bundle.js 並搜尋 「Hi JSX!」,就能看見他在一片程式海中:
雖然被編譯後的程式碼很亂,但仍然可以在裡面找出一些端倪,就是 createElement
,而 createElement
不是別的,它正是 React 內的頂層 API,這裡可以查看 官方文件 內的說明:
這邊就如同上方說的,瀏覽器只看得懂三種語言,分別是 HTML、CSS 與 JavaScript,因此 Babel 也只是將讀到的 JSX 再轉為真正的 JavaScript 寫法,如果沒有 Babel,等於就得親自使用 React 的 createElement
去寫,就會變得更複雜且沒那麼直觀。
今天的完整內容會放到 GitHub 上,歡迎各位參考!
大概是這三天來最長的一篇,也在前置準備的時候遇到一些小問題,但我還是會好好控制不讓每天的曲線跳得太多,如果對文中 Babel 的使用或操作有任何問題,再麻煩留言告訴我,謝謝大家!
ReactDom.render(document.getElementById('root'), );
這行參數好像相反了,會跳出Error: Minified React error #200
不過Github上的程式碼是正確的
萬分感謝!立馬修正過來!
這個系列很好,對C++人來說比較容易入門,不過JS webpack看上去比C++ xmake複雜的說.....
其實我沒有用過 C++ 的 xmake,所以無法體會到
至於 Webpack 最麻煩的應該就是版本的更新速度和豐富的生態圈可以用吧,導致每篇教學感覺都有一點不一樣