noWebpack的代表:snowpack和vite
“noWebpack”,无bundle的代表:snowpack和vite
前段时间Vue3.0生态的介绍提到了vite这个工具,借此文简单整理记录"no webpack,no bundle"的相关内容。
背景
In
20192020, you should use a bundler because you want to, not because you need to.
在过去的几年中,如webpack 之类的bundle打包工具,已经从一个只限于输出优化bundle JavaScript的工具演变成一个需要为大多数web应用程序构建的必要步骤。不管你喜欢还是讨厌它,很难否认bundlers大幅增加了新web开发的复杂性。
为何会孕育出js捆绑打包的构建时代呢?个人认为有两个主要原因:
- 1.http1.x的队头阻塞,使得合并请求变得很必要:http1.x的情况下,浏览器客户端在同一时间,针对同一域名下的请求有一定数量限制。超过限制数目的请求会被阻塞,从而影响性能,因此合并请求成为了普遍认同的优化原则;
- 2.npm的运作限制。nodejs的模块体系,无论是Common.js 还是 CJS,无法在web浏览器上直接运行,我们必须依赖bundling。
这也导致如今很难看到一个前端项目没有webpack介入,由此一个项目的复杂性也大大增加。以create-react-app为例,我们单纯只想在页面中显示一个"Hello world",但是我们需要安装200.9MB的node_modules,其中包含1,300+不同的依赖,10s~几十s的构建时间,这仅仅只是为了输出一个"Hello world"。
那么基于以上两点,现如今有没有其他更好的处理方式呢?
- 1.http2解决对头阻塞:多路复用作为http2的一大特性,允许同时通过单一的 http2 连接发起多重的请求-响应消息,而且随着 http2 的普及,合并请求变得没那么必要。
- 2.浏览器开始支持ESM模块功能:模块功能的核心
import
和export
,它们在浏览器端现在的兼容情况如下:-
import
:
-
export
:
-
并且作为模块的定义,
<script>
标签需要添加type="module"
属性,其兼容性如下:
-
总体来看,兼容覆盖率还算良好,特别是一些PC如CRM这类不太考虑浏览器兼容的项目可以完全抛开bundle,并且往往也就是这些项目的复杂度和构建时间的消耗更高。
snowpack
Snowpack is a modern, lightweight toolchain for faster web development.
snowpack 项目最初时间约为18年下半年,当前(2020.08.09)最新版本为2.x,标语为不需打包的 O(1)
复杂度的构建系统。其核心特征如下:
- 开发模式启动仅需 50ms 甚至更少。
- 热更新速度非常快。
- 构建时可以结合任何 bundler,比如 webpack。
- 内置支持 TS、JSX、CSS Modules 等。
- 支持自定义构建脚本以及三方插件。
支持情况
- 库:React、Preact、Svelte、Vue、lit-html、lit-element、Styled Components、Tailwind CSS…
- 工具:Babel、TypeScript、PostCSS、Sass、esbuild、11ty…
上手使用
安装
# using npm
npm install --save-dev snowpack
# using yarn
yarn add --dev snowpack
Snowpack 也可以通过全局安装npm install -g snowpack
。但是推荐每个项目使用 --save-dev
/--dev
。
初始化新项目
最简单的项目初始化就是使用Create Snowpack App
类似于create-react-app,通过命令初始化导入项目模板:
npx create-snowpack-app new-dir --template @snowpack/app-template-NAME [--use-yarn | --use-pnpm]
当前官方提供的模板:
- @snowpack/app-template-blank
- @snowpack/app-template-blank-typescript
- @snowpack/app-template-11ty
- @snowpack/app-template-lit-element-typescript
- @snowpack/app-template-lit-element
- @snowpack/app-template-preact
- @snowpack/app-template-react-typescript
- @snowpack/app-template-react
- @snowpack/app-template-svelte-typescript
- @snowpack/app-template-svelte
- @snowpack/app-template-vue
比如初始了一个react项目,其目录结构如下:
其中最为核心的就是snowpack.config.json
,即项目配置文件。
旧项目迁移
拷贝模板项目下“src”和“public”文件到你的旧项目下,安装snowpack并执行snowpack dev
,连接并调整出现的异常即可。
配置
通过 snowpack.config.json
文件配置,并能自动读取 babel.config.json
生效 babel 插件。
详细的配置和使用可见官网使用说明,从开发的角度来说跟以往项目基本无异。
开发调试
调试
snowpack dev
编译
snowpack build
会自动以 src/index 作为应用入口进行编译。
snowpack dev
命令几乎是零耗时的,因为文件仅会在被浏览器访问时进行按需编译,因此构建速度是理想的最快速。如下实际执行的情况:
当浏览器访问文件时,snowpack 会将文件做如下转换:
// Your Code:
import * as React from "react";
import * as ReactDOM from "react-dom";
// Build Output:
import * as React from "/web_modules/react.js";
import * as ReactDOM from "/web_modules/react-dom.js";
目的就是生成一个相对路径,并启动本地服务让浏览器可以访问到这些被 import 的文件。其中 web_modules 是 snowpack 对 node_modules 构建的结果。
在这之前也会对 Typescript 文件做 tsc 编译,或者 babel 编译。
编译命令 snowpack build 默认方式与 snowpack dev 相同,也可以指定以 webpack 作为构建器:
// snowpack.config.json
{
// Optimize your production builds with Webpack
"plugins": [
[
"@snowpack/plugin-webpack",
{
/* ... */
}
]
]
}
除了默认构建方式之外,还支持自定义文件处理,通过 snowpack.config.json 配置 scripts 指定:
{
"extends": "@snowpack/app-scripts-react",
"scripts": {
"build:scss": "sass $FILE"
},
"plugins": []
}
比如上述语法支持了对 scss 文件编译的拓展。
生产打包
默认情况下,snowpack build
和snowpack dev
效果是一样的,但是在生产环境的打包构建中,我们更希望拥有如tree-shaking等其他优化手段。这时候就需要在snowpack.config.json 中配置bundler 插件,比较常用的就是@snowpack/plugin-webpack
npm install @snowpack/plugin-webpack
// snowpack.config.json
{
// Optimize your production builds with Webpack
"plugins": [["@snowpack/plugin-webpack", {/* ... */}]]
}
基本原理
snowpack是一个TypeScript项目,主要的三方依赖是rollup。
与webpack不同,snowpack独立处理文件,当文件更新时,snowpack也是只会跟新这个文件,而不是像webpack一样重新构建。这样的开发模式称为"Unbundled development"。
Unbundled development有以下优点:
- 单文件构建更快;
- 单文件构建更准确;
- 单文件构建更容易debug;
- 项目规模并不影响开发速度;
- 单个文件缓存更好。
从它的处理流程上来看,对业务代码的模块,基本只需要把 ESM 发布(拷贝)到发布目录,再将模块导入路径从源码路径换为发布路径即可。
而对 node_modules 则通过遍历 package.json 中的依赖,按该依赖列表为粒度将 node_modules 中的依赖打包。以 node_modules 中每个包的入口作为打包 entry,使用 rollup 生成对应的 ESM 模块文件,放到 web_modules 目录中,最后替换源码的 import 路径,是得可以通过原生 JavaScript Module 来加载 node_modules 中的包。
vite
The faster frontend build tool. Unbundled web development.
vite这个项目开始时间约为2020年初,现在(2020-08-09)处于beta试用版,
其核心特征如下:
- 快速的冷启动;
- 即时的模块热更新;
- 真正的按需编译。
vite与snowpack类似,并且还有一部分依赖来自于snowpack v1。相比之下vite列出相比snowpack的优势是:
- 1.ESM HMR热更新的支持更早;
- 2.在需要bundle打包的时候,vite使用rollup,snowpack是以Parcel/webpack插件,vite更快更容易;
- 3.Vue支持程度更好。
上手使用
安装及初始化
npm:
npm init vite-app <project-name>
cd <project-name>
npm install
npm run dev
yarn:
yarn create vite-app <project-name>
cd <project-name>
yarn
yarn dev
基本原理
感觉与snowpack类似,也是一个TS项目,都是对单文件进行处理,核心使用了Koa。
选型和展望
从特性的构建流程来看看,vite 和 snowpack 十分接近,从现阶段来说,snowpack更加成熟,对框架的支持更好,而vite肯定对vue3生态的支持契合度更好,但是当前建设不够成熟。
简单来说,在vite和snowpack的选型中,如果你的项目是基于Vue的,那么就选择vite,react、Svelte的话还是使用snowpack吧。
那么现在应该使用snowpack/vite吗?
个人认为在大部分业务场景中还是否定的,总的原因还是兼容问题。不过可以尝试在开发环境使用snowpack/vite以提升构建速度,在生产仍然使用bundle模式。不过配置项不同也要承担一定风险:
- 开发与生产环境构建结果不一致的风险;
- 项目生态存在非 ESM import 模块化包而导致大量适配成本的风险;
- 项目存在大量 webpack 插件的 magic 魔法,导致标准化后丢失定制打包逻辑的风险。
不过未来比较明确的是,nowebpack即使不能成为主流也一定能占一席之地。
相关链接
- https://www.pika.dev/blog/pika-web-a-future-without-webpack
- https://stackoverflow.com/questions/985431/max-parallel-http-connections-in-a-browser/985704#985704
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Modules
- https://www.snowpack.dev/
- https://github.com/vitejs/vite
- https://github.com/open-wc/open-wc
- https://www.snowpack.dev/posts/2020-05-26-snowpack-2-0-release/