前言
如果網站的規模不大,可能單純寫一支 all.js 就能搞定了,但如果今天與別人合作或者網站規模比較大,這時若只單靠一支 all.js 肯定是落落長的程式碼,每次要修改就得找半天,這樣是非常辛苦的。所以我們需要模組化 JavaScript ,這樣會方便很多,而模組化的好處遠不只這些,就不贅述了。
把檔案分開就好嗎 ? 這我以前就這麼做了!
這邊的模組化的意思並不是把程式碼拆成多支 .js 檔並且在 index.html 內引入,因為這麼做其實並不算真正的把檔案分開,在 JavaScript 內仍然把它們視為同一個檔案,只是堆疊在一起,就好比這樣:
前置作業
- 準備一支 index.html ,並且引入兩支檔案
- math.js 內容如下
- all.js 內容如下
於是輸出結果,會發現 all.js 會把寫在 math.js 內的全域變數給印出來,這代表程式執行時它們會拼合成一支檔案,而透過觀察這麼做會產生 2 次的 request ,因為用了兩次的 script 標籤。
使用 ES5 export 與 require
接著我們使用 ES5 module.exports
與 require
試著將 math.js 模組化…。
你會發現根本不能運行,因為 module.exports 與 require 只有 node.js 環境下才可以使用。
不管是 ES5 module.exports
與 require
或 ES6 import
與 export
,如果想在瀏覽器環境使用模組化 JavaScript 就必須透過 Webpack 來搞定!
於是我們需要做一些事前準備:
- 下載安裝 npm - 可以到 node.js 下載安裝包
打開 CLI 輸入 node -v
,若出現版本號代表安裝成功。
- 切換到上個範例的資料夾內,輸入
npm install webpack webpack-cli — save -dev
接著可以到 webpack 官網看看如何起手
好的,我們要先在專案資料夾內建立一個叫做 webpack.config.js 的檔案,接著複製貼上這些程式碼,而這些程式碼的涵義也很簡單:
entry
: 進入點,代表引用這些 modules 最主要的地方path
: 檔案輸出的路徑filename
: 檔名
都設置完之後,大致上長這個樣子:
接著回到 index.html ,引用我們打包後的 bundle.js 檔案
這樣事前準備就都完成了,終於可以進入使用 ES5 module.exports 與 require 的部分。
- 首先在 math.js 內使用 module.exports 將函式匯出
- 接著 all.js 把檔案 require 進來
- 最後別忘了執行
.\node_modules\.bin\webpack
打包產生檔案
接著我們就可以到瀏覽器上觀察囉~
發現函式的確成功的呼叫了,而且並不會受到 math.js 內的全域變數干擾,而且也因為只有使用一次 script 標籤,因此 request 只有一次。
想匯出的不只一支函式?可以建立物件來達成!
math.js 內配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14var math = '我是全域變數,會影響到其他人';
function double(num){
return num*2;
}
function triple(num){
return num*3;
}
module.exports = {
double: double,
triple: triple,
};all.js 內配置
1
2
3
4const myModule = require('./module/math');
console.log(myModule.double(10));
console.log(myModule.triple(10));
console.log(math);
因為匯出的東西是物件,所以我們也必須使用物件的方式來取用。
別忘了使用指令打包輸出,接著來看看結果:
蠻簡單的,對嗎?
使用 ES6 export 與 import
使用 ES6 比較尷尬的點是,有些流覽器並沒有完全支援 ES6 語法,因此必須使用 ES5 或者透過 Babel 來轉換 ES6 的語法,目前 export
與 import
支援的程度如下:
嗯…好像還是紅紅的,所以要使用之前還是得先查一下支援程度,或者就乾脆使用 Babel 搞定這一切。
怎麼使用
- math.js 配置
- all.js 配置
可以看出跟 ES5 的差別在哪裡:
- 函式前面可以加上
export
代表匯出該函式 - 使用
import {}
承接, {} 內變數名稱需與匯出的函式相同 - 可以
export
的東西不只函式,變數也可以
除了這樣子寫以外,還有一些變化
- import 可以使用
*
號配合as
賦予別名
而這個 myModules
是什麼呢?
是個物件,所以可以像一般使用物件的方式一樣操作即可。
- 不想每個函式都加上
export
,可以這麼做
這邊要特別注意的是
export{ }
並不是物件
export
配合default
,就可以import
時不加 { } ,但只能有一個default。
是不是覺得 import 沒有 { } 感覺比較順手呢?
心得
個人比較喜歡取 import *
號取別名配合 export{ }
的方式,感覺最順手。
ES6 雖然好用歸好用,不過這樣的方式似乎目前支援度還是蠻差的,還是得透過 Babel ,如果確定專案會用上 Babel 了,那就不用客氣的用吧!
如果不想使用 Babel 那就使用 ES5的 require
+ module.exports
囉。
這邊撞了蠻多牆的,因為一開始很單蠢,不知道模組化必須得透過 Webpack 才能進行,還很納悶的想說語法都沒錯怎麼不能跑。