ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Rails 6 时代的 Webpacker 完整指南:用 Webpack 为 Rails 引入现代 JavaScript 打包、依赖管理与按需加载

Rails 6 时代的 Webpacker 完整指南:用 Webpack 为 Rails 引入现代 JavaScript 打包、依赖管理与按需加载 Rails 6 时代的 Webpacker 完整指南用 Webpack 为 Rails 引入现代 JavaScript 打包、依赖管理与按需加载【免费下载链接】curriculumThe open curriculum for learning web development项目地址: https://gitcode.com/GitHub_Trending/cu/curriculum本篇技术指南以本仓库归档课程 archive/ruby_on_rails/webpacker.md 为主体系统讲解 Rails 6 中 Webpacker 的定位、Pack 机制、Yarn 依赖管理、依赖图原理及其与 Asset Pipeline 的差异并结合仓库内 JavaScript 与 Rails 相关课程源码级佐证帮助你理解这一历史性解决方案的完整全貌。学完本文你将掌握Webpack 依赖图的构建方式、app/javascript/packs目录下的 Pack 文件组织方法、如何在视图层用javascript_pack_tag按需加载 JavaScript以及如何使用 Yarn 为 Rails 项目引入 npm 生态的第三方库。背景Asset Pipeline 的成就与局限Rails 的 Asset Pipeline 是一项非常出色的特性本仓库的 ruby_on_rails/assets_and_navigation/asset_pipeline.md 对其有专门讲解它让编写 CSS 与 JavaScript 变得简单并自动完成所有样式表与脚本文件的打包拼接工作。但它并非没有缺点——接入最新 JavaScript 语言特性往往需要等待很久而通过 gem 加载流行 JavaScript 库与框架的方式也常常落后于前端社区的更新节奏。这给 Rails 带来了可靠但过时的声誉尤其是在 JavaScript 社区已经在构建一个远比过去声誉所显示的更好用的生态的大背景下。与此同时Webpack 作为面向现代 JavaScript 应用的静态模块打包器static module bundler被创造出来它让 JavaScript 变得更容易处理开发时便于阅读的代码经过处理后可以转换成更适合浏览器在生产环境运行的形态。更重要的是Webpack 能够与 Node 包管理器npm协同工作从而接入海量的 JavaScript 库并且这些库一经发布即可更新无需再等待中间层的同步。正是这种来自前端生态的压力促使 Rails 给出了自己的答案——Webpacker。Webpacker 是什么约定优于配置的 Webpack 封装Webpacker 是一个 Ruby gem它的作用是为 Rails 提供一层与 Webpack 直接协作的包装器wrapper。借助它Rails 得以坚持自己约定优于配置convention over configuration的信条为 Webpack 提供一组合理的默认配置同时让使用 Rails 的开发者获得访问整个 npm 仓库的能力。从设计意图上看Webpacker 被明确设计为与 Asset Pipeline 并行工作Asset Pipeline 仍然负责样式表、图片以及少量小型 JavaScript 脚本Webpack 则被视为**应用级 JavaScriptapp-like JavaScript**的最佳载体——也就是那些用来为 Web 应用编写大规模功能模块的代码。在版本演进上Rails 6 及以上版本中 Webpack 已成为默认方案而在 Rails 5 中可以通过在 Gemfile 中添加该 gem 并执行初始化命令来集成。仓库中的课程 ruby_on_rails/rails_sprinkles/js_bundling.md 对此补充道Webpacker 之所以在 Rails 6 时代被采用是因为当时 ES6ECMAScript 6需要经过转译才能在浏览器中使用而 Webpacker 正是承担了这一转译与打包职责的官方 gem。核心机制依赖图Dependency Graph理解 Webpacker首先要理解 Webpack 的核心工作方式。Webpack 在处理文件时会构建一张依赖图dependency graph它绘制出你的 JavaScript 代码的完整地图包括代码所依赖的第三方库然后基于这张图生成代码束bundle。这一概念与本仓库 JavaScript 课程的讲解一脉相承——javascript/organizing_your_javascript_code/webpack.md 明确指出打包时我们为打包器提供一个入口点entry point打包器从该文件出发构建依赖图把所有相关文件合并最终输出一个包含全部必要代码的单一文件。Webpacker 在 Rails 中做的事情正是如此从 Pack 入口文件开始递归解析所有import/require的模块最终产出可在浏览器运行的打包结果。关于入口点 依赖图 输出 bundle的完整链路可参见 javascript/organizing_your_javascript_code/webpack.md 中的基础讲解Webpacker 只是把这条链路以 Rails 约定的方式固定了下来。Pack 机制从 app/assets/javascript 到 app/javascript/packs在 Asset Pipeline 时代JavaScript 文件存放在app/assets/javascript目录而在 Webpacker 时代取而代之的是所谓的packs。它们存放在app/javascript/packs目录是你想在应用中使用的 JavaScript 代码的入口点。这是 Asset Pipeline 与 Webpacker 之间的一个关键差异Asset Pipeline所有 JavaScript 代码被捆绑进一个巨大的文件唯一的例外是用于 Ajax 请求的代码可以在请求到达时再执行因此所有文件都必须被引用进application.js。该文件会在客户端首次连接服务器时整体下载。Webpackerpacks可以拥有任意数量的 pack 文件每个 pack 只在其真正需要的页面被下载。例如处理表单客户端校验的代码对于一个从不访问该表单页面的用户来说是不需要的——用 Asset Pipeline 它会在首次页面加载时被下载而用 Webpack 只需在对应视图view中引用该 pack它只会在有人访问表单页面时被加载。在视图中引用 Packjavascript_pack_tag在只有 Asset Pipeline 的时代新建 Rails 应用会在app/views/layouts/application.html.erb中生成以下两行% stylesheet_link_tag application, media: all, data-turbolinks-track reload % % javascript_include_tag application, data-turbolinks-track reload %这两行把app/assets/stylesheets与app/assets/javascript目录下的application.css、application.js文件捆绑在一起。而使用 Webpack 与 packs 的 Rails 6 应用生成的则是% stylesheet_link_tag application, media: all, data-turbolinks-track reload % % javascript_pack_tag application, data-turbolinks-track reload %两行代码非常相似——实际上stylesheet_link_tag完全相同因为 Rails 默认仍用 Asset Pipeline 处理 CSS变化在于 JavaScript 改用javascript_pack_tag它默认在app/javascript/packs目录中查找此处即查找application并加载application.jspack 文件。与 Asset Pipeline 要求一切代码都必须在application文件中被引用的方式不同使用 Webpack 可以按需引入一个或多个 pack 文件只需在packs目录中放置一个 pack 文件然后在需要的视图中引用它即可。例如假设有一段用于处理联系表单提交的代码我们不希望它在每个页面都被加载。于是在packs目录创建contact_form.jspack 文件再在表单视图的页面底部放置% javascript_pack_tag contact_form, data-turbolinks-track reload %Pack 文件与普通 JavaScript 文件有什么不同Pack 文件与普通 JavaScript 文件本质上没有区别它们就是普通的 JS 文件——真正的差异在于用途定位。一个 Pack 文件应当只负责从 JavaScript 目录的其他位置加载代码从 Rails 安装项目rails installation car project的application.jspack 文件可以看到它的唯一职责就是require其他文件并在必要时初始化它们。回到contact_form这个例子可以创建一个app/javascript/contact_form/目录里面存放管理联系表单的实际业务代码然后在 pack 文件中简单地import或require类似../contact_form/whatever_file_we_need的文件。注意这里使用了../——因为从 pack 目录出发需要向上移动一级才能找到contact_form目录。安装 JavaScript 库Yarn 与 package.json在 RubyGems 生态中我们使用 Gemfile 管理依赖而在 Webpacker 生态中则使用package.json管理 JavaScript 库。两者的主要区别在于操作方式使用 Gemfile 时需要手动打开文件添加 gem 及版本号然后运行bundle使用 Webpack 时可以直接在终端用 Yarn 添加库例如添加 Bootstrapyarn add bootstrapYarn 会替我们处理其余一切并自动更新package.json文件。正如 gem 可以只安装到 testing 或 development 分组一样JavaScript 包也可以只用于开发环境而不进入生产环境。典型的例子是测试库jest——生产代码中并不需要它。安装时只需加上--dev选项yarn add --dev jestnode_modules 与版本复现所有包都被安装到node_modules文件夹。这个文件夹以代码黑洞著称打开需谨慎。由于其体积可能非常庞大node_modules默认被排除在 git 版本控制之外。取而代之的是当你克隆一个项目后只需要使用package.json和 Yarn 重新生成node_modules文件夹。在 Pack 中引用已安装的库安装好库之后还需要在 pack 文件中引用它。Webpack 将node_modules文件夹视为顶级搜索目录因此在引用库时不必从 pack 文件位置一层层回溯无需写出require ../../node_modules/etc这样的路径直接以库在 node_modules 中的名字开头引用即可require bootstrap/bootstrap说明这里的require语法沿用了原课程示例。在现代 ESM 风格的代码中对应的写法是import bootstrap或import bootstrap/dist/js/bootstrap等无论哪种形式模块解析机制都是相同的——Webpack 会优先在node_modules中查找裸模块标识符bare module specifier。关于 ESM 导入与模块解析规则的更多背景可参考 javascript/organizing_your_javascript_code/webpack.md 中关于 import 文件扩展名的说明。其他资源让 Webpack 处理 CSSstylesheet_pack_tag虽然 Rails 目前的意图是让 Webpack 只负责应用级 JavaScript、其余资源仍由 Asset Pipeline 处理但用 Webpack 处理全部资源也是可行的。这种情况下可以把stylesheet_link_tag改为stylesheet_pack_tag% stylesheet_pack_tag application, media: all, data-turbolinks-track reload % % javascript_pack_tag application, data-turbolinks-track reload %此时可以在application.js中require任意 CSSRails 会将其作为 CSS 加载并由 Webpack 一起打包。课程同时给出了务实的建议如果确实要这样做请先深入研读 Webpack 本身以及它如何处理各类资源在那之前除 JavaScript 之外的资源仍建议沿用 Asset Pipeline。这一点与仓库中 javascript/organizing_your_javascript_code/webpack.md 关于 CSS 加载的讲解互为印证——Webpack 通过css-loader读取 CSS 文件、style-loader将样式注入页面非 JavaScript 资源需要额外的 loader/规则配置才能被正确打包。依赖图每个 Pack 独立构建与重复打包问题使用 Webpacker 时一个值得注意的关键点是它如何决定加载哪些代码。在 Asset Pipeline 中因为所有代码都必须加载进application.jsRails 只需构建一张覆盖全部代码的依赖图并确保任何代码都不会被包含两次。一个典型例子如果你的应用使用了 jQuery而某个第三方库也依赖 jQuery 并将其列为自己的依赖Asset Pipeline 会确保 jQuery 只被加载一次避免代码臃肿。而Webpack 会为每一个 pack 文件分别构建依赖图因此如果不同的 pack 文件都require了同一个库就可能出现同一份代码被重复打包进不同 pack的情况——这会显著增大客户端的总下载量。避免这一问题的办法有若干种但对初学者而言最简单的是只使用默认的application.jspack 文件。当所有需要的代码都包含在唯一一个 pack 中时依赖图便只从这一个文件构建Webpack 会确保对其中的代码进行优化天然杜绝重复包含。历史位置Webpacker 的来龙去脉与后续演进从本仓库的多个课程可以拼出 Webpacker 的完整历史定位ruby_on_rails/assets_and_navigation/importmap.md 指出在 Rails 7 之前JavaScript 第三方包的管理长期是个难题。最初的做法是把 JavaScript 封装进 Ruby gem 发布虽带来了版本化与稳定性但更新滞后——必须等待 gem 维护者更新、测试并发布新版本。Rails 6 尝试以 Webpacker 这个围绕 webpack 的包装 gem 解决该问题利用 Rails 著名的约定优于配置提供合理的默认配置但同时指出其核心弊端若想脱离这些约定就需要对 Webpacker 有更深入的理解。遗憾的是它并未完全解决当初想解决的问题于是新的方案应运而生。ruby_on_rails/rails_sprinkles/js_bundling.md 进一步确认Webpacker 作为 Rails 6 时代的方案被使用了数年而Rails 7 已不再使用它取而代之的是jsbundling-rails提供 esbuild、rollup、webpack 三种打包器选项以及默认的 import maps 方案。ruby_on_rails/assets_and_navigation/asset_pipeline.md 则从资产管线角度补充了背景在 ES6 被主流浏览器广泛支持、HTTP/2 可用单条 TCP 连接承载多个请求之后转译与拼接的价值被大幅削弱Asset Pipeline 也由sprockets演进为更精简的propshaft。因此学习 Webpacker 的价值在于大量现存 Rails 6 应用仍在生产环境使用它理解 pack、依赖图、javascript_pack_tag与 Yarn 工作流能让你在面对这些代码库时游刃有余同时它也构成了理解 Rails 7 之后 JS 打包方案import maps 与 jsbundling-rails的历史坐标。学习自测围绕本课程的核心知识可以用以下问题检验自己的掌握程度什么是 Webpack它与 Asset Pipeline 有何不同如何在 Rails 项目中添加 JavaScript 库Webpack 是如何构建依赖图的什么是 pack 文件它与普通 JavaScript 文件有何区别为什么多个 pack 可能导致同一库被重复打包如何规避小结Rails 的一切都围绕约定优于配置展开因此你应该能以最小的成本上手 Webpacker并经由它使用 Webpack。在熟悉它的过程中坚持使用数量有限的 pack 文件尤其是默认的application.js即可避开重复打包的陷阱从而顺畅地处理应用中的 JavaScript 代码。对于想要继续深挖的读者仓库中的 javascript/organizing_your_javascript_code/webpack.md 与 javascript/organizing_your_javascript_code/revisiting_webpack.md 提供了不依赖 Rails 的 Webpack 原生配置实战可作为理解 Webpacker 底层机制的补充读物。【免费下载链接】curriculumThe open curriculum for learning web development项目地址: https://gitcode.com/GitHub_Trending/cu/curriculum创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表