snowpack,提高 10 倍打包速度的神奇工具

引言

前幾天聽一個朋友說到 snowpack, 便去去看了下這個包是幹什麼的,看了下官網,發現這個東西還是蠻有意思的。號稱 無需打包工具(Webpack,Parcel)便能將代碼結果實時展現在瀏覽器中。可以先看以下的圖,是不是很誘人?

snowpack 以 ES Modules 爲主,如果對 ES Modules 不熟悉的朋友,請先查看我的上一篇文章。

爲什麼使用 snowpack

在 ESM 出現之前,JavaScript 的模塊化就有各式各樣的規範,主要有 CommonJS, AMD, CMD, UMD 等規範,最爲廣泛的就是 Node.js 的 CommonJS,使用 module.exports 和 require 來導出導入模塊,它是 npm 中的模塊最主要提供的格式。由於瀏覽器並不直接支持這些模塊,因此打包工具(Webpack,Browserify,Parcel 等)出現了。

  1. 在開發過程中你是否遇到 webapp 總是需要等待才能看到結果,每次保存後電腦就非常瘋狂。2.webpack 之類的打包工具功能非常強大,他們引入配置,插件,依賴成本很低,任意創建一個 react 應用便將要安裝 200M 的依賴包,並且需要寫很多行的 webpack 配置。3.ESM 在瀏覽器中使用了大約 5 年的時間,現在在所有現代瀏覽器中都受支持(可追溯到 2018 年初)。使用 ESM,不再需要打包工具。您可以在沒有 Webpack 的情況下構建一個現代化,高性能,可用於生產的 Web 應用程序!4. 你只需安裝運行一次 snowpack 替換 Webpack,Parcel 等繁雜的打包工具,可以獲得更快的開發環境,並減少工具複雜性。

環境支持

由於默認情況下,snowpack 將 npm 依賴項安裝爲 ES 模塊 (ESM),那麼 ES 模塊的支持情況怎麼樣了呢?

不用擔心,目前使用的 90% 的瀏覽器都支持 ESM 語法。自 2018 年初以來,所有現代瀏覽器 (Firefox、Chrome、Edge、Safari) 都支持 ESM。

示例

需要環境: Node 10 +

基礎

說了這麼多,就是說方便唄。那麼我來實際操作一下。

先以一個 react 項目爲例

mkdir snowpack-demo
cd snowpack-demo
npm init -y

安裝依賴

npm i @babel/cli @babel/core @babel/preset-react servor snowpack -D
npm i react@npm:@pika/react react-dom@npm:@pika/react-dom -S
// src/index.js
import React, { useState } from "react";
import ReactDOM from "react-dom";
function App() {
    return (
      <div>hello world</div>
    );
}
window.addEventListener("load", () =>
  ReactDOM.render(<App />, document.getElementById("app"))
);
<div></div>
<script type="module" src="/dist/index.js"></script>
npx snowpack
babel src/ --out-dir dist
npx servor --reload

打開 http://localhost:8080

進階

使用 css

由於瀏覽器不支持直接使用 JS 導入 CSS, 因此以下代碼無法使用。

// ✘ NOT SUPPORTED OUTSIDE OF BUNDLERS
import './style.css';

如果想要引入 css, 需要通過 style 標籤直接引入資源。

官方推薦的使用方式是

  1. 簡單應用,使用內斂 style2. 複雜應用推薦使用 CSS-in-JS

因此這裏採用 styled-components

npm i styled-components -S
npx snowpack

修改 index.js

import React, { useState } from "react";
import ReactDOM from "react-dom";
import styled from 'styled-components';
const UI = styled.div`
    color: red
`
function App() {
    return (
      <UI>
        hello world
      </UI>
    );
}
window.addEventListener("load", () =>
  ReactDOM.render(<App />, document.getElementById("app"))
);

修改下 package.json

"start": "babel src/ --out-dir dist --watch & servor --reload"
npm run start

使用圖片

// ✘ NOT SUPPORTED OUTSIDE OF BUNDLERS
import './photo.png';

如今,沒有瀏覽器支持直接從 JS 導入圖像。相反,您將要使用以下庫 / 解決方案之一:

<img src="/img/photo.png">

使用 TypeScript

npm i @babel/preset-typescript typescript -D

修改 .babelrc

{
    "presets": ["@babel/preset-react", "@babel/preset-typescript"],
    "plugins": [
        "snowpack/assets/babel-plugin.js"
    ]
}

將 src/index 修改成 src/index.tsx 並加入聲明。

import React, { useState } from "react";
import ReactDOM from "react-dom";
import styled, { ThemeProvider } from 'styled-components';
const ThemeColor = {
  default: 'red'
}
interface Theme {
  themeColor: typeof ThemeColor
}
const UI = ({ children }: { children?: React.ReactNode }) => {
  return (
    <>
      <ThemeProvider theme={ThemeColor}>{children}</ThemeProvider>
    </>
  );
};
const AppStyle = styled.div<Theme>((props: Theme) => {
  console.log(props);
  return {
    color: props.theme.default
  }
})
function App() {
  return (
    <UI>
      <AppStyle>
        hello world
      </AppStyle>
    </UI>
    );
}
window.addEventListener("load", () =>
  ReactDOM.render(<App />, document.getElementById("app"))
);

修改 啓動命令,讓 babel 包含對 後綴 tsx 的轉義。

{
  "start": "babel src/ --out-dir dist --watch --extensions \".ts,.tsx,.js,.jsx\" & servor --reload"
}

優化

默認情況下,snowpack會安裝最小化的依賴關係並針對開發進行了優化。準備好進行生產時,請使用--optimize標誌運行snowpack以啓用某些僅針對生產的優化:

  1. 最小化依賴關係 2. 轉義低級語法 3.Tree-Shaking(通過--include啓動自動模式)4. 支持舊版瀏覽 --nomodule

如果要構建單頁應用程序(SPA),請使用--nomodule運行 snowpack 並傳入應用程序入口點。然後,在你的應用程序中創建第二個腳本標籤, 帶有nomodule 標識的入口。

<!-- Ignored by legacy browsers: -->
<script type="module" src="/src/index.js"></script>
<!-- Ignored by modern browsers: -->
<script nomodule src="/web_modules/app.nomodule.js"></script>

完成此操作後,運行 snowpack 生成一個 / web_modules/app.nomodule.js 腳本,這個腳本會自動在舊的舊版瀏覽器上運行。

緩存處理

通過傳入 addVersion

/* .babelrc */
"plugins": [
  ["snowpack/assets/babel-plugin.js", {"addVersion": true}],
]

可以輸出帶有版本號的腳本

// src/ File Input
import Foo from 'package-name';
// lib/ Babel Output
import Foo from '/web_modules/package-name.js?v=1.2.3';

結尾

snowpack 優勢

  1. 減少了打包的時間成本,只要一次 snowpack。修改源碼能夠實時反饋在瀏覽器上。2. 代碼可移植能力強,相當於純寫 JavaScript 語言。3. 模塊和源碼相互獨立,有點類似於 webpack 的 DDL。4. 對於簡單應用可以快速搭建,對於一些在線編輯的網站可以使用類似的方案進行構建。

snowpack 劣勢

  1. 對 ES Modules 的依賴性強,在 npm 上雖然 ES Modules 的包在逐漸增加,但是短期內需要包都需要做額外的處理。例如我想引入 Antd, 發現其中依賴了很多 CommonJS 的模塊以及樣式未使用 CSS-in-JS, 引入較爲繁瑣。

  1. 對於一些 cssimages 資源處理不夠友好,需要額外手動處理,並且底層使用 rollup 來進行一次 ES Modules 的導出太過於生硬, 沒有強大的自定義的插件或者配置。2. 太多依賴包會造成網絡問題

以上例子:https://github.com/hua1995116/snowpack-demo

對於現階段的 snowpack 來說還是太年輕,但是年輕總是充滿希望和可能。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/pUgbKYmolQS0kYUCLeprng