背景
最近对脚手架技术架构的升级改造, 虽然在构建速度方面提升了3+倍, 接入项目的大佬们也都甚为满意, 毕竟还是没能达到秒级的开发体验。想着这算到了 webpack 的瓶颈了, 要去调研更快的打包工具及落地的可能性了。
现状
新的脚手架对 webpack 的构建速度优化简述为以下几点, 后面可以单独展开分享一下
- 多线程
- 前置构建
- 多页面动态编译/单页多路由动态编译
- loader缓存/plugin缓存
- 持久缓存
参赛工具
Parcel
其实一直是写 demo 的首选, 说要落地到生产, 没想过 … 官网上宣传的速度只是 webpack 的两倍左右, 加上仅存的三两项目遇到的一些 bug(陆续也转到了 webpack), 算上社区的活跃度,没有实践的动力。
对 parcel 的评估只是个人的经验, 缺乏数据说明。话说回来即使是稳定且健壮的 parcel 也是达不到我们最初的秒级的开发体验。
小结: parcel 仍然不适合中大型项目。
Snowpack
终于回到了本次的主题, 为什么说 snowpack 快 ? 它是希望你能写出浏览器直接能运行的代码, 你说它能不快吗 … 当然还是要有理有据, 看看官方解释。
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.
主要帮我们做了什么
# 1. 把项目依赖的 node_modules 模块通过 rollup 编译成 esm 标准代码输出到
build/web_modules 目录
# snowpack/src/commands/dev.ts#297
// 如果是不存在 'package-lock.json' 或者 'yarn.lock'|| 'package-lock.json' 或者 'yarn.lock' 有变化 || 第一次构建 等情况会重新编译
if (!(await checkLockfileHash(DEV_DEPENDENCIES_DIR)) || !existsSync(dependencyImportMapLoc)) {
// ...
}
# 2. 通过 babel 编译 ts, tsx, js, jsx 代码输出到 build/_dist_ 目录(毕竟浏览器跑不了 jsx, ts 代码)
# plugins/plugin-babel/worker.js#4
async function transformFileAsync(path, options) {
const {code, map} = await babel.transformFileAsync(path, options);
return JSON.stringify({code, map});
}
// 使用如下文件的 babel 配置
# app-scripts-react/babel.config.json
// 实践证明 @babel/preset-typescript 坑不少, 老项目上线几个白屏几个
{
"presets": [["@babel/preset-react"], "@babel/preset-typescript"],
"plugins": ["@babel/plugin-syntax-import-meta"],
"env": {
"development": {
"plugins": [
"react-refresh/babel"
]
}
}
}
# 3. 开发环境启动一个 devServer
# snowpack/src/commands/dev.ts#875
const server = createServer((req, res) => {
// ...
})
demo 目录结构对比
➜ new-dir tree src
src
├── App.css
├── App.jsx
├── App.test.jsx
├── index.css
├── index.jsx
├── logo.svg
└── test.css
➜ new-dir tree build
build
├── __snowpack__
│ └── env.js
├── _dist_
│ ├── App.css
│ ├── App.js
│ ├── index.css
│ ├── index.css.proxy.js
│ ├── index.js
│ ├── logo.svg
│ ├── logo.svg.proxy.js
│ └── test.css
├── favicon.ico
├── index.html
├── robots.txt
└── web_modules
├── import-map.json
└── react-dom.js
发现的一些问题
- 源码可能会被篡改
# plugins/plugin-babel/plugin.js#42
code = code.replace(/process\.env/g, 'import.meta.env');
// 会造成如下问题
// src
function getEnvLabel() {
return 'process.env.NODE_ENV'
}
// dist
function getEnvLabel() {
return 'import.meta.env'
}
// enum ....
- css 文件 @import 另一个 css 文件不会处理
没有进行 ast 语法分析, 你只能在 js 文件里面 import, 也许你想着帮忙一起完善这块, 到了日趋完善的一天发现之前不就有一个成熟的 webpack 为何不用 ? 这 …
- ….
小结
现在的 snowpack 还是希望你能写出浏览器直接能运行的代码, 对于新小项目开发环境可尝试, 其他还是先等一等 …