打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
搞懂為何設定 React、JSX、ES2015、Babel、Webpack 的學習筆記 | 轉個彎日誌

學習 React、JSX、ES2015、Babel、Webpack 等等現代化的前端開發觀念時,會需要安裝很多工具、設定多個檔案、用到許多指令。

大部份教學文章只講「怎麼設定這些」而沒說明「為何要設定這些」。照著做完感覺很不放心。

最近我試著搞懂「為何要設定這些」,跟大家分享一下這個逐步搞懂的過程。

前言

這篇文章假設你想要開始用 React 開發,希望搞懂相關的前端環境與設定。

如果你想知道用 React 到底有什麼好處,可以參閱以下連結:

Introducing JSXThinking in React簡單聊一下 ONE-WAY DATA FLOW、TWO-WAY DATA BINDING 與前端框架

接下來,這篇文章會以試著寫一個陽春的 App 元件作為範例,內含 ChildA 跟 ChildB 兩個元件。

讓我們開始吧!

第一步:直接在 html 檔內開發 React 給瀏覽器執行

我們先用原始的開發方法硬搞看看!

用 script 標籤直接從 CDN 引入 react.js 跟 react-dom.js 檔案。

然後試著寫一個陽春的 App 元件,內含 ChildA 跟 ChildB 兩個元件。

這個 html 檔內容會像這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<script crossorigin src="https://unpkg.com/react@15/dist/react.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@15/dist/react-dom.js"></script>
<script>
  class App extends React.Component {
    render() {
      return (
        <div>
          <h1>Hello App!</h1>
          <ChildA />
          <ChildB />
        </div>
      );
    }
  }
  class ChildA extends React.Component {
    render() {
      return <h2>Child A</h2>;
    }
  }
  class ChildB extends React.Component {
    render() {
      return <h2>Child B</h2>;
    }
  }
  ReactDOM.render(
    <App />,
    document.getElementById('app')
  );
</script>
<div id='app'>
    Should Render Here
</div>

source code

結果瀏覽器無法執行 React 相關的程式碼!

原因有兩個:

1. 瀏覽器看不懂 ES2015 的語法(class、extends)

2. 瀏覽器看不懂那個像是把 html 寫在 js 裡面的 JSX 語法

該怎麼辦呢?

第二步:用 Babel 讓瀏覽器能看懂 ES2015 與 JSX 語法

我們可以使用 Babel 套件來來編譯 ES2015 與 JSX 的程式碼,讓瀏覽器能夠看懂。

只要在 html 內加上這行:

然後在要編譯的 script 加上 type=’text/babel’ 即可:

1
<script type='text/babel'>

就可以順利執行我們的 React 程式了!

source code

您可以用這種方式開發一些小型的 React 程式。

但實務上這些元件會複雜、龐大很多,全部寫在HTML裡面的話,不但很難維護,還有 babel 每次都在瀏覽器內編譯的效能問題。

只有3個元件可能還好,但要是有30個元件呢?

拆開成獨立檔案,並且預先用 babel 編譯過比較好。

第三步:把檔案拆開,並且預先編譯完成

把3個元件各自獨立成檔案,也把啟動這些元件的程式碼獨立成一個檔案:

1
2
3
4
/src/App.jsx
/src/ChildA.jsx
/src/ChildB.jsx
/src/index.jsx

接著來預先編譯它們。

這次我們不使用上面瀏覽器版本的 babel,我們用命令列介面的 babel-cli 來編譯。

先安裝好 babel-cli:

1
npm init

1
npm install --save-dev babel-cli

然後 babel-cli 從版本 6 之後預設不支援 ES2015 與 JSX,需要分別加裝所謂的「preset」才行:

1
npm install --save-dev babel-preset-es2015

1
npm install --save-dev babel-preset-react

接著就能在命令列使用 babel 並且設定 presets 來編譯了。

我們有4個檔案,所以分別打編譯指令4次:

1
./node_modules/.bin/babel --presets es2015,react src/App.jsx -o dist/App.js

1
./node_modules/.bin/babel --presets es2015,react src/ChildA.jsx -o dist/ChildA.js

1
./node_modules/.bin/babel --presets es2015,react src/ChildB.jsx -o dist/ChildB.js

1
./node_modules/.bin/babel --presets es2015,react src/index.jsx -o dist/index.js

成功編譯之後,就不需要在瀏覽器內引入 babel 了,直接使用編譯完成的檔案即可:

1
2
3
4
5
6
7
8
9
10
11
12
<script src='/dist/App.js'></script>
<script src='/dist/ChildA.js'></script>
<script src='/dist/ChildB.js'></script>
<div id='app'>
    Should Render Here
</div>
<script src="/dist/index.js"></script>

source code

然而,這樣做卻又產生3個新的問題:

1. 有N個檔案,就要打編譯指令N次,太累了

2. 透過 script 標籤引入N個檔案,會增加伺服器負擔、也會增加用戶端等待時間

3. babel 相關的程式碼都移出瀏覽器了,react.js 跟 react-dom.js 卻還是在瀏覽器內引入

第一個問題還算簡單,可以改成輸入指定資料夾的指令,就可一次編譯:

1
./node_modules/.bin/babel src/ -d dist/ --presets es2015,react

但是第二三個問題就棘手得多。

有鑑於此,需要找方法一次解決這三個問題:設法一口氣全部編譯、封裝成單一檔案、並且函式庫統一用NPM在伺服器端安裝與管理吧!

第四步:使用 webpack 來解決這些整合問題

webpack 會利用 babel-loader 套件來呼叫核心的 babel-core,所以先分別安裝它們:

1
npm install --save-dev babel-core

1
npm install --save-dev babel-loader

1
npm install --save-dev webpack

我們不會透過命令列去使用 babel 了,既然用不到就先把它移除吧:

1
npm uninstall babel-cli

我們也不會用 script 標籤引入 react.js 跟 react-dom.js 檔案了。一口氣全部編譯時會用到,所以用NPM安裝它吧:

1
npm install --save-dev react

1
npm install --save-dev react-dom

前面說過 babel 版本 6 以後預設不支援 ES2015 與 JSX,現在不透過命令列設定 presets 的話,就需要建立 .babelrc 檔案去開啟支援:

1
2
3
{
  "presets": ["es2015", "react"]
}

然後為了讓 webpack 在一口氣全部編譯成一個檔案時,能看懂檔案跟套件之間的相依性,因此需要按照 ES2015 的 import/export 語法寫清楚。

例如原本的 App.jsx 就要改寫成這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import React from 'react';
import ChildA from './ChildA.jsx';
import ChildB from './ChildB.jsx';
export default class App extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello App!</h1>
        <ChildA />
        <ChildB />
      </div>
    );
  }
}

src 資料夾內的檔案都要進行改寫。

最後建立 webpack.config.js 來設定檔案路徑,並指定使用 babel-loader 來幫忙編譯:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var path = require('path');
module.exports = {
  module: {
    loaders: [{
      loader: 'babel-loader',
    }]
  },
  entry: './src/index.jsx',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, './dist/')
  }
}

就可以透過命令列執行 webpack了:

1
./node_modules/.bin/webpack

這段指令有點長,可以把它放進 package.json 的 scripts 欄位:

1
2
3
  "scripts": {
    "build": "webpack"
  },

之後就可以用下列指令來進行編譯工作了:

1
npm run build

會得到我們要的結果:一個檔案搞定一切!

1
2
3
4
5
<div id='app'>
    Should Render Here
</div>
<script src="/dist/bundle.js"></script>

source code

大功告成!終於搞定我們想要的所有效果!

結語

本篇文章提到的內容,根據不同的套件版本,實務上有多種方式去安裝、設定達到同樣效果。

但是核心觀念是共通的!

可以此為基礎,探索更多的現代前端開發方法,學習更多工具的功能與設定!

(完)

(Photo via 8 Kome, CC licensed.)

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
现代Web开发需要学习的15大技术
在2016 年学 JavaScript 是一种什么样的体验?
一个小时搭建一个全栈Web应用框架
【第651期】React.js 初学者应该知道的 9 件事
React项目从Javascript到Typescript的迁移经验总结
原来你是这样的 Vue
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服