Browser 上的 ESmodule & 現代化的前端構建工具 Snowpack / Vite

瀏覽器看得懂 import / export 耶!支援程度如何?對資深前端打工仔 aka 網頁開發者來說又有什麼改變?未來的打包趨勢跟當今的 solution 又有何不同呢?

realdennis
8 min readNov 22, 2020

大致上談幾件事

  • Browser 上原生的 import / export 怎麼用、原理
  • Support 程度
  • 對前端工程化影響
  • 適用 ESM 之打包工具——Snowpack / Vite

寫在前面

本文將會以速食般的速度,不廢話的講重點,不會加入太多前提解釋。

適合閱讀的受眾:

  • 已經了解前端工程化
  • 了解當代打包工具功能的前端打工仔。

不適合閱讀本文:

  • (Tune 模板)只有在 HTML 嵌入過 Bootstrap/jQuery
  • (前端新人)沒有 build 過 npm package 到瀏覽器上
  • (來自 2008 年的時空穿越者)以為前端只能寫幾個按鈕給 User submit

Browser 上的 import / export

你熟悉的 ESModule , import xxx from ‘ooo’ / export default ,現在可以跑在瀏覽器上,說現在其實不太精確,其規格在 ES6 就定好了。(靠北, 2015 欸!)

註:開發者都是傾向於寫 ESModule 的語法,再透過 Babel 這類的工具把它轉成 Node 可以看懂的 CommonJS (require / module.exports = {})。

啊怎麼用?

首先 HTML 上,這段要用 ESModule 的 script 必須要長這樣:

<script type="module" src="js/index.js">

你的 JS 裡頭就可以用 import / export 了

import helloworld from './helloworld.js'
helloworld()

而 helloworld.js 就是:

export default ()=> {
console.log("hello world");
}

你的 static folder 大概長這樣

├── index.html
└── js
├── helloworld.js
└── index.js

不相信嗎?我 Code 都寫好了,直接來 Verify 吧,沒混直接發。

啊不是,是沒 bundle 直接發。

ESModule 的 支援度如何?

https://caniuse.com/?search=es6-module

IE 就不用想了,不過號稱當代手機界的IE—Safari是支持的呢。

這個支援度…好像滿猛的耶?如果不考慮 IE 這個爛東西,似乎可以朝著 ESModule 的路筆直向前了!

ESModule 跟以往的體驗差異

我們從上面的廢物 Demo 了解到:

  • 所有的模組都是 static 的 js file
  • 瀏覽器會 Handle relative /absolution URL 並加載模組的過程

這意味著幾件事情:

  • Code splitting
  • Decrease file size
  • Network concurrent fetch

ESmodule 對前端工程化的影響

傳統的前端工程化(如Webpack 、 Parcel) 等等的 bundler 都是將整個code 、 dependency 塞到單一一隻 JS File 載入。

註:儘管可以透過宣告方式做 Code Splitting 、 lazy loading,但無論是前者可以被 ESModule 的分拆解決,或是後者可以透過原生的 import() 解決。

這也意味著,當你選擇了 ESmodule 作為開發,你對於 build time 需要去處理的 Effort 大大降低,再也不需要雜亂的 Bundler 配置、設定 Entry file 等等的,只要透過 <script type=module> 就可以進入具 module dependency 的 JS code。

但實際上有這麼理想嗎? node_modules 的 packages / CSS的預處理 / babel transform / typescript …工程化還有這麼多件事,難道只能繼續捆綁在 Webpack 了?

我們仍然需要有 build tool 在 build time 時幫我們:

  • 把 package dependency 放到對應的 static folder裡頭
  • 做一些預處理的動作(包括 .ts/.jsx /.scss /.sass / …)

Snowpack — modern bundler

Snowpack is a modern frontend build tool for faster web development. It replaces heavier, more complex bundlers like webpack or Parcel in your development workflow.

Snowpack leverages JavaScript’s native module system (known as ESM) to create a first-of-its-kind build system that never builds the same file twice. Snowpack pushes changes instantly to the browser, saving you hours of development time traditionally spent waiting around for your bundler.

以上在 Build time 需要完成的事情 Snowpack 都可以透過其原始的功能或者對應的 Plugin (你也可以想象成 Loader)去做掉。

有趣的是他們解決 node_modules 的方法,如果你試著透過 snowpack 來 build 你的 index.js 如下:

// src/index.js// The below three is from node_modules
import rQUI from 'rQUI';
import carousel from 'rQUI.carousel';
import animation from 'rQUI.animation';
// The below one is what you create and import
import elements from './elements.js';

最終 build 出來的 _dist_/index.js 會是

// _dist_/index.js
import rQUI from '/web_modules/rQUI/index.js';
import carousel from '/web_modules/rQUI.carousle/index.js';
import animation from '/web_modules/rQUI.animation/index.js';

你的 public folder 會是這樣的 file structure:

├── _dist_
│ └── js
│ ├── elements.js
│ └── index.js
├── index.html
└── web_modules
├── rQUI
│ └── index.js
├── rQUI.carousel
│ └── index.js
└── rQUI.a
└── index.js

屆時這些東西會一路從 public folder server 到 web 上,而 Browser 在吃到 ESModule 後會自動發起網路請求,並且把這些東西 collect 回來 as module。

另外一個一樣風格的 build tool —Vite

無獨有偶也是走 ESM 形式的 build tool,雖不熟悉,但我剛 init 了一個來看看,一樣的方式,我們透過 source/network tab 可以發現是相似的 file structure:

後記

大型網站其實很早就有拆分 JavaScript 的邏輯,包括早期的 CDN,以及 Webpack 的 code splitting,總是先有需求,才有解法,最終變成規格。如同React & Vue 之於 Web Components, ESmodule 的出現的確是一大救贖,並且搭配良好的 HTTP Server tuning,可以達到非常優秀的頁面載入速度 / 效能。

--

--