
Jekyll 的 Ruby 基石Gems、Gemfile 与 Bundler 全解【免费下载链接】jekyll:globe_with_meridians: Jekyll is a blog-aware static site generator in Ruby项目地址: https://gitcode.com/gh_mirrors/je/jekyll本文围绕 Jekyll 官方文档 Ruby 101 展开面向刚接触 Ruby 生态的 Jekyll 开发者系统讲解 Gem、Gemfile、Bundler 三个核心概念的职责与协作方式并结合本仓库的 gemspec、jekyll new命令源码与插件加载逻辑说明 Jekyll 在不同环境中如何锁定版本、安装依赖并加载 gem 插件读完你既能看懂任何一个 Jekyll 项目的依赖声明也能理解bundle exec jekyll serve背后发生的事情。Jekyll 本身就是一个 GemRuby 生态中Gem 是代码分发的基本单元Gems 是可以包含在 Ruby 项目中的代码包它将特定功能打包成可复用、可跨项目共享的模块。一个 Gem 能做的事情很多例如将 Ruby 对象转换为 JSON实现分页逻辑与 GitHub 等外部 API 交互。Jekyll 自身就是以 Gem 的形式发布的。从 jekyll.gemspec 可以看到它声明了包名jekyll、版本号来自 lib/jekyll/version.rb当前仓库版本为4.4.1、MIT 许可证、可执行文件目录exe/对应 exe/jekyll 命令行入口以及对 Ruby 版本的要求s.required_ruby_version 2.7.0 s.required_rubygems_version 2.7.0gemspec 还列出了 Jekyll 的全部运行时依赖这也是理解一个 Gem 由其他 Gems 组成的最好范例s.add_runtime_dependency(addressable, ~ 2.4) s.add_runtime_dependency(kramdown, ~ 2.3, 2.3.1) s.add_runtime_dependency(kramdown-parser-gfm, ~ 1.0) s.add_runtime_dependency(liquid, ~ 4.0) s.add_runtime_dependency(rouge, 3.0, 5.0) s.add_runtime_dependency(webrick, ~ 1.7) # ... 还有 base64、colorator、csv、em-websocket、i18n、jekyll-sass-converter、 # jekyll-watch、json、logger、mercenary、pathutil、safe_yaml、terminal-table 等从中可以读出几个关键事实Jekyll 的模板语言是liquid~ 4.0表示 4.x 兼容版本Markdown 解析交给kramdownkramdown-parser-gfm本地开发服务器jekyll serve由webrick提供语法高亮由rouge完成。这些依赖在bundle install时会一并被解析安装——这正是 Bundler 的价值所在。Gemfile一个 Jekyll 站点的依赖清单Gemfile是列出站点所用全部 Gems 的文件按照惯例放在项目根目录。Jekyll 官方文档给出的最简示例是这样的source https://rubygems.org gem jekyll group :jekyll_plugins do gem jekyll-feed gem jekyll-seo-tag end其中source指定 Gem 的来源仓库顶层gem声明核心依赖group :jekyll_plugins则把 gem 插件归入一个特殊分组——这个分组在 Jekyll 中有特殊地位后文源码部分会详细解释。除jekyll-feed、jekyll-seo-tag外Jekyll 生态中常用的插件 Gem 还有jekyll-archives、jekyll-paginate、jekyll-sitemap等。jekyll new实际生成的 Gemfile本仓库中的jekyll new命令会为新站点自动写入一份带版本约束和平台适配的 Gemfile其模板定义在 lib/jekyll/commands/new.rb 的gemfile_contents方法中生成的内容大致如下source https://rubygems.org # Hello! This is where you manage which Jekyll version is used to run. # When you want to use a different version, change it below, save the # file and run bundle install. Run Jekyll with bundle exec, like so: # # bundle exec jekyll serve # gem jekyll, ~ 4.4.1 # 锁定当前大版本 gem minima, ~ 2.5 # 新站点的默认主题 # If you want to use GitHub Pages, remove the gem jekyll above and # uncomment the line below. To upgrade, run bundle update github-pages. # gem github-pages, group: :jekyll_plugins group :jekyll_plugins do gem jekyll-feed, ~ 0.12 end # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem # and associated library. platforms :mingw, :x64_mingw, :mswin, :jruby do gem tzinfo, 1, 3 gem tzinfo-data end # Performance-booster for watching directories on Windows gem wdm, ~ 0.1, :platforms [:mingw, :x64_mingw, :mswin] # Lock http_parser.rb gem to v0.6.x on JRuby builds... gem http_parser.rb, ~ 0.6.0, :platforms [:jruby]这份模板体现了几个官方推荐的实践版本约束gem jekyll, ~ 4.4.1用乐观约束符固定大版本避免不兼容的自动升级平台条件依赖Windowsmingw/x64_mingw/mswin与 JRuby 缺少时区数据文件因此按需引入tzinfo-dataWindows 下用wdm提升文件监听性能github-pages注释行面向 GitHub Pages 部署场景提示把gem jekyll换成gem github-pages, group: :jekyll_plugins使站点与 Pages 使用的 Jekyll 版本保持一致。本仓库自身的 Gemfile 则展示了开发型项目更复杂的分组方式group :development调试工具 pry 等、group :testrspec、cucumber、测试用主题 fixture、group :jekyll_optional_dependencies如jekyll-paginate、jekyll-feed、kramdown-syntax-coderay、group :site用于构建文档站的jekyll-seo-tag、jekyll-sitemap等。可见分组group是组织运行时依赖 / 开发依赖 / 可选依赖的标准手法。Bundler把 Gemfile 落地为一致的运行环境Bundler 是一个专门管理 Gemfile 的 Gem负责安装、锁定并加载Gemfile中声明的全部依赖。虽然 Jekyll 不强制要求使用 Gemfile 和 Bundler但官方强烈建议——它能确保你在不同机器、不同环境中运行的是完全相同版本的 Jekyll 与插件从根上消除在我机器上能跑的问题。Bundler 只需安装一次它随 RubyGems 生态安装而非每个项目装一遍gem install bundler随后在包含 Gemfile 的目录中执行bundle install bundle exec jekyll servebundle install根据Gemfile以及锁定文件Gemfile.lock解析并安装所有依赖bundle exec让后续命令如jekyll serve、jekyll build运行在项目锁定的 Gem 环境里而不是系统全局环境。如果没有使用 Gemfile直接运行jekyll serve即可绕过 Bundler。更完整的从零开始bundle init、bundle config set --local path vendor/bundle、bundle add jekyll、bundle exec jekyll new --force --skip-bundle .以及.gitignore建议请参阅官方教程 Using Jekyll with Bundler。源码透视jekyll new如何自动执行 bundle installjekyll new PATH创建站点脚手架后会自动尝试运行bundle install。在 lib/jekyll/commands/new.rb 中def after_install(path, options {}) unless options[blank] || options[skip-bundle] begin require bundler bundle_install path rescue LoadError Jekyll.logger.info Could not load Bundler. Bundle install skipped. end end ... end def bundle_install(path) Jekyll.logger.info Running bundle install in #{path.cyan}... Dir.chdir(path) do exe Gem.bin_path(bundler, bundle) process, output Jekyll::Utils::Exec.run(ruby, exe, install) ... end end要点除非你传了--blank生成空站点或--skip-bundle跳过安装否则jekyll new会自动执行bundle install若系统中没有 Bundler命令会优雅降级仅打印 Could not load Bundler. Bundle install skipped.不会中断建站流程--force允许在目录已存在且非空时强制覆盖这也是 Bundler 教程中bundle exec jekyll new --force --skip-bundle .需要这两个参数的原因——先bundle init生成的目录并非空目录而提前存在的 Gemfile 会让 Jekyll 跳过自身写入模板的动作所以先跳过、建站完成后手动bundle install。tests/test_new_command.rb 中的用例验证了这条链路新站点必须生成包含gem jekyll, ~ 当前版本的 Gemfile、输出 Running bundle install in ... 的成功提示、--blank模式不触发 bundle install、--skip-bundle输出 Bundle install skipped.、路径参数缺失时抛出ArgumentError。源码透视Jekyll 如何在构建时感知 Bundlerbundle exec jekyll serve之所以能加载 Gemfile 中声明的插件关键在 lib/jekyll/plugin_manager.rb 的PluginManager.require_from_bundlerdef self.require_from_bundler if !ENV[JEKYLL_NO_BUNDLER_REQUIRE] gemfile_exists? require bundler Bundler.setup required_gems Bundler.require(:jekyll_plugins) message Required #{required_gems.map(:name).join(, )} Jekyll.logger.debug(PluginManager:, message) ENV[JEKYLL_NO_BUNDLER_REQUIRE] true true else false end end # Check for the existence of a Gemfile. def self.gemfile_exists? File.file?(Gemfile) || (ENV[BUNDLE_GEMFILE] File.file?(ENV[BUNDLE_GEMFILE])) end从这段实现可以确认三件事只有当工作目录或BUNDLE_GEMFILE环境变量指向的位置存在 Gemfile 时Jekyll 才会在启动流程中激活 Bundler 环境:jekyll_plugins分组被无条件 requireBundler.require(:jekyll_plugins)会把该分组内的 gem 在所有构建包括--safe模式中提前加载这解释了为什么 Gemfile 示例把jekyll-feed、jekyll-seo-tag放进这个分组JEKYLL_NO_BUNDLER_REQUIRE环境变量用于避免重复激活可作为调试时的旁路开关。而常规路径下gem 插件列入_config.yml的plugins:键插件由 PluginManager#require_gems 按需加载并受 safe 模式白名单约束def require_gems Jekyll::External.require_with_graceful_fail( site.gems.select { |plugin| plugin_allowed?(plugin) } ) end新建站点的模板配置 lib/site_template/_config.yml 中就有对应的声明# Build settings theme: minima plugins: - jekyll-feed也就是说_config.yml的plugins:决定哪些已安装的 gem 参与本次构建Gemfile 决定哪些 gem 以及什么版本被安装二者配合才构成完整的插件加载机制_plugins目录、_config.yml与 Gemfile 三条插件路径也可以同时使用。更多细节见 插件安装文档。小结三个概念如何协作概念角色关键命令/文件Gem功能打包单元可跨项目复用jekyll.gemspec声明运行时依赖Gemfile站点依赖清单声明 Gem 及版本约束source、gem、group :jekyll_pluginsBundler依赖解析与安装器锁定一致环境bundle install、bundle exec推荐的工作流是gem install bundler安装一次 Bundler每个站点用jekyll new自动生成 Gemfile 并自动bundle install或bundle initbundle add jekyll起步日常开发统一使用bundle exec jekyll serve等命令Gemfile与Gemfile.lock提交进版本库vendor/、.bundle/加入.gitignore。掌握这套机制后你就能理解 Jekyll 各环境间版本一致性的来源也能自如地为站点增删 gem 插件。【免费下载链接】jekyll:globe_with_meridians: Jekyll is a blog-aware static site generator in Ruby项目地址: https://gitcode.com/gh_mirrors/je/jekyll创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考