iT邦幫忙

2021 iThome 鐵人賽

DAY 3
1
Modern Web

前端黑洞計畫 (一) : 讓 Vite 來開啟你的Vue系列 第 3

Day_03 : 讓 Vite 來開啟你的Vue 微談模組化與演進(下)

  • 分享至 

  • xImage
  •  

Hi Da Gei Ho~ 我是 Winnie , 今天來到了第三天

前情提要:

在昨天的文章中,我們簡單的解釋了下 模組 與 模組化 是什麼之後,今天我們將繼續 簡單了解 JS模組化規範 的 演進過程。

不知道大家記不記得,在上篇的文章我們有說到 早期的JavaScript 是還沒有模組化的概念的,所以在當時 只能以function 檔案來區分並透過<script><script/> 的方式來載入,就像以下程式碼:

//Monday.js
function Monday(month, day){
return month+"/"+day
}

//Tuesday.js
function Tuesday(month, day){
return month+"/"+day
}

//Wednesday.js
function Wednesday(month, day){
return month+"/"+day
}

<html lang="en">
  <body>
    <script type="text/javascript" src="../lib/juqery.js"></script>
    <script type="text/javascript" src="../js/Monday.js"></script>
    <script type="text/javascript" src="../js/Tuesday.js"></script>
    <script type="text/javascript" src="../js/Wednesday.js"></script>
  </body>
</html>

**依照上面程式碼載入的方式,如果使用不小心很容易就會導致以下缺點:

  • 命名的衝突 導致污染全域
    //a.js
    var Wednesday = '9/15'
    .... 略
    //b.js
     var Wednesday = '9/16'
    ....略
    console.log(Wednesday) 

從上程式碼來看,原本應該 星期三應該是9/15,但因為其他命名相同的衝突而被覆蓋 輸出 9/16

  • 引入的檔案相互依賴性高,順序很重要

    如:Wednesday.js 依賴了Tuesday.js 那麼載入時就必須先使用Tuesday.js再使用Wednesday.js,一但順序相反,就很容易出錯

IIFE

後來為解決 命名衝突及污染全域的問題 ,進而發展出 IIFE(立即執行函式) 模擬模組的方式,而IIFE的就如同他名字一樣,當下被宣告function就會立即執行

其中在模擬模組化的過程中,還 使用到了 JavaScript的特性 閉包Closures 讓區域變數和方法鎖在內部,將需要給外部使用的變數傳出去,而這樣的好處就是區域性的變數 就不會汙染到全域性作用域

(function(){
    var name = 'winnie;
    var sayHello = function (){
        console.log('hello ! I'm'+ name);
    }
    sayHello(); // hello! I'm winnie
})()

雖然以上 實現了簡單的程式碼模組化,同時也解決了污染作用域的問題,但針對 管理 相互依賴的問題還是依然存在。

所以隨著技術的進步(老話一句),為了能讓人們更方便,所以後期在 Node.js 中大家也開始發展出許多方便的第三模組庫供人使用,因此針對模組化也有了不同的規範版本,其中 像是 我們常聽到的 CommonJSAMDCMD 還有 近期的ES6 module

而在這麽多規範中,想必大家應該常常會看到 require/module.exportsimport/exports 的用法吧?

是的!接著我們就要來介紹這兩個的規範,分別是 common.js & ES6 module (抱歉!其實 AMD、CMD也常見,後續有機會會再補上 )

ES5 之前 的 Common JS

如果大家有印象,在 Common JS標準最主要的規範就是輸出模組時用 module.exports,引入時用 require

範例如下:


// banana.js

//一個一個 匯出

exports.banana = 'I m banana'
module.exports.banana = function(){}

//整體匯出
module.exports = {  banana: 'I m banana', banana:function(){}}



const banana = require('./banana.js')
console.log(banana.banana) // 'I m banana'

而這個用法在當時也被Node.js採用 ,所以現今我們時常會在各種程式碼中 看到這個形式來做模組的輸出與引用。
但很可惜的是,雖然Common.js被Node.js採用成模組化的規範,但很可惜的是,在瀏覽器上面依然沒辦法使用 ,簡單來說 就是 瀏覽器 只看得懂 JavaScript 啊,而這也是我們 現今為何要使用 打包工具 的最主要原因。

對!終於提到 打包工具,現在你終於能稍微知道為什麼要用Webpack了啊!

畫重點!!就是在當時 瀏覽器的原生並不支援 CommonJS),必須透過打包工具的編譯 才能在瀏覽器上面使用。

ES6 Module

而 ES6 出來之後,模組化 有了正式的規範,也就是近期很常看到的 import 與 export的形式

範例如下:

// hello.js
// 多個輸出名稱
  export function sayHello(){  
  console.log('Hello');
}

  export function sayBye(){  
  console.log('Bye');
}

// 單一輸出  (這邊需注意的是 一隻檔案中只能有一個 export default)

function sayGoodnight(){
  console.log(‘Goodnight’)
}

export default sayGoodnight

---------------------------------
// other.js
// 引入hello模組的sayHello方法
  import { sayHello, sayBye } from './hello';
  sayHello(); // => Hello
  sayBye(); // => Bye

這就是 ES6 Module 。

到這邊,你可能會想既然原生都支持了,為何還要打包工具?

但事情是這樣的,人生有十之八九不會照著我們想走的走。

所以在 ES6 Module 這邊也是一樣,雖然是瀏覽器原生支持的,但還是有在某些瀏覽器不支援的問題,就像下面這張圖一樣

而同時如果在 Node.js 上面試圖執行 import 這個語法,也還出現一個 SyntaxError: Unexpected identifier 的錯誤,因為 Node.js 不認識 import。但總不可能因為不支援就要拋棄他人寫好的給力模組吧。

綜合以上這些可能會碰到的問題,如果想要人生順利,我們還是需要透過 打包工具 來幫我們處理掉這些問題。

小結:

最後,這篇文章簡單的針對 JS中 模組化從有到無的出現過程及常見模組化規範(其實還少講了很多XD,像是AMD、CMD)進行了描述,雖然可能不是說得很詳細,但這篇文章的最主要目的還是想透過 模組化的微歷史 來了解 為何使用打包工具來編譯的目的。

如果文章有錯誤的地方,再麻煩不吝嗇的給予指教 謝謝 !!


上一篇
Day_02: 讓 Vite 來開啟你的Vue 微談模組化與演進(上)
下一篇
Day_04 : 讓 Vite 來開啟你的Vue_ Module Bundler
系列文
前端黑洞計畫 (一) : 讓 Vite 來開啟你的Vue30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言