作者:AlienZHOU
转发链接:https://zhuanlan.zhihu.com/p/149351900
目录
带你了解 snowpack 原理,你还学得动么(上)
带你了解 snowpack 原理,你还学得动么(下)本篇
小编建议小伙们从第一篇开始,按照顺序来看,更清晰明了。
这里我将 HMR 和样式注入的代码省去了,只保留了 CSS Module 功能的部分。可以看到,它其实是借力了 css-modules-loader-core 来实现的 CSS Module 中 token 生成这一核心能力。以创建的 React 模板为例,将 App.css 改为 App.module.css 使用后,代码中会多出如下部分:
+ let json = {"App":"_dist_App_module__App","App-logo":"_dist_App_module__App-logo","App-logo-spin":"_dist_App_module__App-logo-spin","App-header":"_dist_App_module__App-header","App-link":"_dist_App_module__App-link"};+ export default json;
对于导出的默认对象,键为 CSS 源码中的 classname,而值则是构建后实际的 classname。
3.6. 性能问题
还记得雅虎性能优化 35 条军规么?其中就提到了通过合并文件来减少请求数。这既是因为 TCP 的慢启动特点,也是因为浏览器的并发限制。而伴随着前端富应用需求的增多,前端页面再也不是手工引入几个 script 脚本就可以了。同时,浏览器中 JS 原生的模块化能力缺失也让算是火上浇油,到后来再加上 npm 的加持,打包工具呼之欲出。webpack 也是那个时代走过来的产物。
随着近年来 HTTP/2 的普及,5G 的发展落地,浏览器中 JS 模块化的不断发展,这个合并请求的“真理”也许值得我们再重新审视一下。去年 PHILIP WALTON 在博客上发的「Using Native JavaScript Modules in Production Today」就推荐大家可以在生产环境中尝试使用浏览器原生的 JS 模块功能。
「Using Native JavaScript Modules in Production Today」 这篇文章提到,根据之前的测试,非打包代码的性能较打包代码要差很多。但该实验有偏差,同时随着近期的优化,非打包的性能也有了很大提升。其中推荐的实践方式和 snowpack 对 node_modules 的处理基本如出一辙。保证了加载不会超过 100 个模块和 5 层的深度。
同时,由于业务技术形态的原因,我所在的业务线经历了一次构建工具迁移,对于模块的处理上也用了类似的策略:业务代码模块不合并,只打包 node_modules 中的模块,都走 HTTP/2。但是没有使用原生模块功能,只是模块的分布状态与 snowpack 和该文中提到的类似。从上线后的性能数据来看,性能并未下降。当然,由于并非使用原生模块功能来加载依赖,所以并不全完相同。但也算有些参考价值。
3.7. JSX / Typescript / Vue / Less …
对于非标准的 JavaScript 和 CSS 代码,在 webpack 中我们一般会用 babel、less 等工具加上对应的 loader 来处理。最初版的 snowpack 并没有对这些语法的处理能力,而是推荐将相关的功能外接到 snowpack 前,先把代码转换完,再交给 snowpack 构建。
而新版本下,snowpack 已经内置了 JSX 和 Typescript 文件的处理。对于 typescript,snowpack 其实用了 typescript 官方提供的 tsc 来编译。
对于 JSX 则是通过 @snowpack/plugin-babel 进行编译,其实际上只是对 @babel/core 的一层简单包装,机上 babel 相关配置即可完成 JSX 的编译。
const babel = require("@babel/core");module.exports = function plugin(config, options) { return { defaultBuildScript: "build:js,jsx,ts,tsx", async build({ contents, filePath, fileContents }) { const result = await babel.transformAsync(contents || fileContents, { filename: filePath, cwd: process.cwd(), ast: false, }); return { result: result.code }; }, };};
从上面可以看到,核心就是调用了 babel.transformAsync 方法。而使用 @snowpack/app-template-react-typescript 模板生成的项目,依赖了一个叫 @snowpack/app-scripts-react 的包,它里面就使用了 @snowpack/plugin-babel,且相关的 babel.config.json 如下:
{ "presets": [["@babel/preset-react"], "@babel/preset-typescript"], "plugins": ["@babel/plugin-syntax-import-meta"]}
对于 Vue 项目 snowpack 也提供了一个对应的插件 @snowpack/plugin-vue 来打通构建流程,如果去看下该插件,核心是使用的 @vue/compiler-sfc 来进行 vue 组件的编译。
此外,对于 Sass(Less 也类似),snowpack 则推荐使用者添加相应的 script 命令:
"scripts": { "run:sass": "sass src/css:public/css --no-source-map", "run:sass::watch": "$1 --watch"}
所以实际上对于 Sass 的编译直接使用了 sass 命令,snowpack 只是按其约定语法对后面的指令进行执行。这有点类似 gulp / grunt,你在 scripts 中定义的是一个简单的“工作流”。
综合 ts、jsx、vue、sass 这些语法处理的方式可以发现,snowpack 在这块自己实现的不多,主要依靠“桥接”已有的各种工具,用一种方式将其融入到自己的系统中。与此类似的,webpack 的 loader 也是这一思想,例如 babel-loader 就是 webpack 和 babel 的桥。说到底,还是指责边界的问题。如果目标是成为前端开发的构建工具,你可以不去实现已有的这些子构建过程,但需要将其融入到自己的体系里。
也正是因为近年来前端构建工具的繁荣,让 snowpack 可以找到各类借力的工具,轻量级地实现了构建流程。
4. 最后聊聊
snowpack 的一大特点是快 —— 全量构建快,增量构建也快。因为不需要打包,所以它不需要像 webpack 那样构筑一个巨大的依赖图谱,并根据依赖关系进行各种合并、拆分计算。snowpack 的增量构建基本就是改动一个文件就处理这个文件即可,模块之间算是“松散”的耦合。
而 webpack 还有一大痛点就是“外部“依赖的处理,“外部”依赖是指:
- 模块 A 运行时对 B 是有依赖关系
- 但是不希望在 A 构建阶段把 B 也拿来一起构建
这时候 B 就像是“外部”依赖。在之前典型的一个解决方式就是 external,当然还可以通过使用前端加载器加载 UMD、AMD 包。或者更进一步,在 webpack 5 中使用 Module Federation 来实现。这一需求的可能场景就是微前端。各个前端微服务如果要统一一起构建,必然会随着项目的膨胀构建越来越慢,所以独立构建,动态加载运行的需求也就出现了。
对于打包器来说,import 'B.js' 默认其实就是需要将 B 模块打包进来,所以我们才需要那么多“反向”的配置将这种默认行为禁止掉,同时提供一个预期的运行时方案。而如果站在原生 JavaScript Module 的工作方式上来说,import '/dist/B.js' 并不需要在构建的时候获取 B 模块,而只是在运行时才有耦合关系。其天生就是构建时非依赖,运行时依赖的。当然,目前 snowpack 在构建时如果缺少的依赖模块仍然会抛出错误,但上面所说的本质上是可实现,难度较打包器会低很多,而且会更符合使用者的直觉。
那么 snowpack 是 bundleless 的么?我们可以从这几个方面来看:
- 它对业务代码的处理是 bundleless 的
- 目前对 node_modules 的处理是做了 bundle 的
- 它仍然提供了 @snowpack/plugin-webpack / @snowpack/plugin-parcel 这样的插件才让你能为生产环境做打包。所以,配合 module/nomodule 技术,它将会有更强的抵御兼容性问题的能力,这也算是一种渐进式营销手段
snowpack 会成为下一代构建工具么?
In 2019, you should use a bundler because you want to, not because you need to.
本篇已完结
推荐JavaScript学习相关文章
《基于Canvas实现的高斯模糊(上)「JS篇」》
《基于Canvas实现的高斯模糊(下)「JS篇」》
《由浅入深,66条JavaScript面试知识点(一)》
《由浅入深,66条JavaScript面试知识点(二)》
《由浅入深,66条JavaScript面试知识点(三)》
《由浅入深,66条JavaScript面试知识点(四)》
《由浅入深,66条JavaScript面试知识点(五)》
《由浅入深,66条JavaScript面试知识点(六)》
《由浅入深,66条JavaScript面试知识点(七)》
《为什么 setTimeout 有最小时延 4ms ?》
《如何处理 Node.js 中出现的未捕获异常?》
《Angular v10.0.0 正式发布,不再支持 IE9/10》
《基于 Docker 的 SSR 持续开发集成环境实践》
《细聊图解webpack 指南手册》
《一文带你彻底搞懂 NPM 知识点「进阶篇」》
《细聊webpack性能优化面面观》
《JS实现各种日期操作方法汇总》
《「实践」细聊前端性能优化总结》
《「实践」浏览器中的画中画(Picture-in-Picture)模式及其 API》
《「多图」一文带你彻底搞懂 Web Workers (上)》
《「多图」一文带你彻底搞懂 Web Workers (中)》
《深入细聊前端下载总结「干货」》
《细品西瓜播放器功能分析(上)「实践」》
《细品西瓜播放器功能分析(下)「实践」》
《细聊50道JavaScript基础面试题「附答案」》
《webpack4主流程源码解说以及动手实现一个简单的webpack(上)》
《webpack4主流程源码解说以及动手实现一个简单的webpack(下)》
《细聊前端架构师的视野》
《细聊应用场景再谈防抖和节流「进阶篇」》
《前端埋点统一接入方案实践》
《细聊微内核架构在前端的应用「干货」》
《一种高性能的Tree组件实现方案「干货」》
《进击的JAMStack》
《前后端全部用 JS 开发是什么体验(Hybrid + Egg.js经验分享)上》
《前后端全部用 JS 开发是什么体验(Hybrid + Egg.js经验分享)中》
《前后端全部用 JS 开发是什么体验(Hybrid + Egg.js经验分享)下》
《一文带你搞懂 babel-plugin-import 插件(上)「源码解析」》
《一文带你搞懂 babel-plugin-import 插件(下)「源码解析」》
《JavaScript常用API合集汇总「值得收藏」》
《推荐10个常用的图片处理小帮手(上)「值得收藏」》
《推荐10个常用的图片处理小帮手(下)「值得收藏」》
《JavaScript 中ES6代理的实际用例》
《12 个实用的前端开发技巧总结》
《一文带你搞懂搭建企业级的 npm 私有仓库》
《教你如何使用内联框架元素 IFrames 的沙箱属性提高安全性?》
《细说前端开发UI公共组件的新认识「实践」》
《细说DOM API中append和appendChild的三个不同点》
《细品淘系大佬讲前端新人如何上王者「干货」》
《一文带你彻底解决背景跟随弹窗滚动问题「干货」》
《推荐常用的5款代码比较工具「值得收藏」》
《Node.js实现将文字与图片合成技巧》
《爱奇艺云剪辑Web端的技术实现》
《我再也不敢说我会写前端 Button组件「实践」》
《NodeX Component - 滴滴集团 Node.js 生态组件体系「实践」》
《Node Buffers 完整指南》
《推荐18个webpack精美插件「干货」》
《前端开发需要了解常用7种JavaScript设计模式》
《浅谈浏览器架构、单线程js、事件循环、消息队列、宏任务和微任务》
《了不起的 Webpack HMR 学习指南(上)「含源码讲解」》
《了不起的 Webpack HMR 学习指南(下)「含源码讲解」》
《10个打开了我新世界大门的 WebAPI(上)「实践」》
《10个打开了我新世界大门的 WebAPI(中)「实践」》
《10个打开了我新世界大门的 WebAPI(下)「实践」》
《「图文」ESLint 在中大型团队的应用实践》
《Deno是代码的浏览器,你认同吗?》
《前端存储除了 localStorage 还有啥?》
《Javascript 多线程编程的前世今生》
《微前端方案 qiankun(实践及总结)》
《「图文」V8 垃圾回收原来这么简单?》
《Webpack 5模块联邦引发微前端的革命?》
《基于 Web 端的人脸识别身份验证「实践」》
《「前端进阶」高性能渲染十万条数据(时间分片)》
《「前端进阶」高性能渲染十万条数据(虚拟列表)》
《图解 Promise 实现原理(一):基础实现》
《图解 Promise 实现原理(二):Promise 链式调用》
《图解 Promise 实现原理(三):Promise 原型方法实现》
《图解 Promise 实现原理(四):Promise 静态方法实现》
《实践教你从零构建前端 Lint 工作流「干货」》
《高性能多级多选级联组件开发「JS篇」》
《深入浅出讲解Node.js CLI 工具最佳实战》
《延迟加载图像以提高Web网站性能的五种方法「实践」》
《比较 JavaScript 对象的四种方式「实践」》
《使用Service Worker让你的 Web 应用如虎添翼(上)「干货」》
《使用Service Worker让你的 Web 应用如虎添翼(中)「干货」》
《使用Service Worker让你的 Web 应用如虎添翼(下)「干货」》
《前端如何一次性处理10万条数据「进阶篇」》
《推荐三款正则可视化工具「JS篇」》
《如何让用户选择是否离开当前页面?「JS篇」》
《JavaScript开发人员更喜欢Deno的五大原因》
《仅用18行JavaScript实现一个倒数计时器》
《图文细说JavaScript 的运行机制》
《一个轻量级 JavaScript 全文搜索库,轻松实现站内离线搜索》
《推荐Web程序员常用的15个源代码编辑器》
《10个实用的JS技巧「值得收藏」》
《细品269个JavaScript小函数,让你少加班熬夜(一)「值得收藏」》
《细品269个JavaScript小函数,让你少加班熬夜(二)「值得收藏」》
《细品269个JavaScript小函数,让你少加班熬夜(三)「值得收藏」》
《细品269个JavaScript小函数,让你少加班熬夜(四)「值得收藏」》
《细品269个JavaScript小函数,让你少加班熬夜(五)「值得收藏」》
《细品269个JavaScript小函数,让你少加班熬夜(六)「值得收藏」》
《深入JavaScript教你内存泄漏如何防范》
《手把手教你7个有趣的JavaScript 项目-上「附源码」》
《手把手教你7个有趣的JavaScript 项目-下「附源码」》
《JavaScript 使用 mediaDevices API 访问摄像头自拍》
《手把手教你前端代码如何做错误上报「JS篇」》
《一文让你彻底搞懂移动前端和Web 前端区别在哪里》
《63个JavaScript 正则大礼包「值得收藏」》
《提高你的 JavaScript 技能10 个问答题》
《JavaScript图表库的5个首选》
《一文彻底搞懂JavaScript 中Object.freeze与Object.seal的用法》
《可视化的 JS:动态图演示 - 事件循环 Event Loop的过程》
《教你如何用动态规划和贪心算法实现前端瀑布流布局「实践」》
《可视化的 js:动态图演示 Promises & Async/Await 的过程》
《原生JS封装拖动验证滑块你会吗?「实践」》
《如何实现高性能的在线 PDF 预览》
《细说使用字体库加密数据-仿58同城》
《Node.js要完了吗?》
《Pug 3.0.0正式发布,不再支持 Node.js 6/8》
《纯JS手写轮播图(代码逻辑清晰,通俗易懂)》
《JavaScript 20 年 中文版之创立标准》
《值得收藏的前端常用60余种工具方法「JS篇」》
《箭头函数和常规函数之间的 5 个区别》
《通过发布/订阅的设计模式搞懂 Node.js 核心模块 Events》
《「前端篇」不再为正则烦恼》
《「速围」Node.js V14.3.0 发布支持顶级 Await 和 REPL 增强功能》
《深入细品浏览器原理「流程图」》
《JavaScript 已进入第三个时代,未来将何去何从?》
《前端上传前预览文件 image、text、json、video、audio「实践」》
《深入细品 EventLoop 和浏览器渲染、帧动画、空闲回调的关系》
《推荐13个有用的JavaScript数组技巧「值得收藏」》
《前端必备基础知识:window.location 详解》
《不要再依赖CommonJS了》
《犀牛书作者:最该忘记的JavaScript特性》
《36个工作中常用的JavaScript函数片段「值得收藏」》
《Node + H5 实现大文件分片上传、断点续传》
《一文了解文件上传全过程(1.8w字深度解析)「前端进阶必备」》
《【实践总结】关于小程序挣脱枷锁实现批量上传》
《手把手教你前端的各种文件上传攻略和大文件断点续传》
《字节跳动面试官:请你实现一个大文件上传和断点续传》
《谈谈前端关于文件上传下载那些事【实践】》
《手把手教你如何编写一个前端图片压缩、方向纠正、预览、上传插件》
《最全的 JavaScript 模块化方案和工具》
《「前端进阶」JS中的内存管理》
《JavaScript正则深入以及10个非常有意思的正则实战》
《前端面试者经常忽视的一道JavaScript 面试题》
《一行JS代码实现一个简单的模板字符串替换「实践」》
《JS代码是如何被压缩的「前端高级进阶」》
《前端开发规范:命名规范、html规范、css规范、js规范》
《【规范篇】前端团队代码规范最佳实践》
《100个原生JavaScript代码片段知识点详细汇总【实践】》
《关于前端174道 JavaScript知识点汇总(一)》
《关于前端174道 JavaScript知识点汇总(二)》
《关于前端174道 JavaScript知识点汇总(三)》
《几个非常有意思的javascript知识点总结【实践】》
《都2020年了,你还不会JavaScript 装饰器?》
《JavaScript实现图片合成下载》
《70个JavaScript知识点详细总结(上)【实践】》
《70个JavaScript知识点详细总结(下)【实践】》
《开源了一个 JavaScript 版敏感词过滤库》
《送你 43 道 JavaScript 面试题》
《3个很棒的小众JavaScript库,你值得拥有》
《手把手教你深入巩固JavaScript知识体系【思维导图】》
《推荐7个很棒的JavaScript产品步骤引导库》
《Echa哥教你彻底弄懂 JavaScript 执行机制》
《一个合格的中级前端工程师需要掌握的 28 个 JavaScript 技巧》
《深入解析高频项目中运用到的知识点汇总【JS篇】》
《JavaScript 工具函数大全【新】》
《从JavaScript中看设计模式(总结)》
《身份证号码的正则表达式及验证详解(JavaScript,Regex)》
《浏览器中实现JavaScript计时器的4种创新方式》
《Three.js 动效方案》
《手把手教你常用的59个JS类方法》
《127个常用的JS代码片段,每段代码花30秒就能看懂-【上】》
《深入浅出讲解 js 深拷贝 vs 浅拷贝》
《手把手教你JS开发H5游戏【消灭星星】》
《深入浅出讲解JS中this/apply/call/bind巧妙用法【实践】》
《手把手教你全方位解读JS中this真正含义【实践】》
《书到用时方恨少,一大波JS开发工具函数来了》
《干货满满!如何优雅简洁地实现时钟翻牌器(支持JS/Vue/React)》
《手把手教你JS 异步编程六种方案【实践】》
《让你减少加班的15条高效JS技巧知识点汇总【实践】》
《手把手教你JS开发H5游戏【黄金矿工】》
《手把手教你JS实现监控浏览器上下左右滚动》
《JS 经典实例知识点整理汇总【实践】》
《2.6万字JS干货分享,带你领略前端魅力【基础篇】》
《2.6万字JS干货分享,带你领略前端魅力【实践篇】》
《简单几步让你的 JS 写得更漂亮》
《恭喜你获得治疗JS this的详细药方》
《谈谈前端关于文件上传下载那些事【实践】》
《面试中教你绕过关于 JavaScript 作用域的 5 个坑》
《Jquery插件(常用的插件库)》
《【JS】如何防止重复发送ajax请求》
《JavaScript+Canvas实现自定义画板》
《Continuation 在 JS 中的应用「前端篇」》
作者:AlienZHOU
转发链接:https://zhuanlan.zhihu.com/p/149351900