Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions .github/workflows/update-bootstrap.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Update Bootstrap

# Daily pull of new dist files from upstream twbs/bootstrap. If the tracked
# branch has moved, re-import the assets, sync the version, verify the
# stylesheets still compile, and commit the result.

on:
schedule:
- cron: '0 6 * * *' # every day at 06:00 UTC
workflow_dispatch:
inputs:
branch:
description: Upstream twbs/bootstrap branch to track
required: false
default: v6-dev

permissions:
contents: write

concurrency:
group: update-bootstrap
cancel-in-progress: false

jobs:
update:
runs-on: ubuntu-latest
env:
BUNDLE_GEMFILE: ${{ github.workspace }}/test/gemfiles/rails_7_0_dartsass.gemfile
UPSTREAM_BRANCH: ${{ github.event.inputs.branch || 'v6-dev' }}
steps:
- uses: actions/checkout@v6

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.4'
bundler-cache: true

- name: Import latest Bootstrap and sync version
id: update
run: |
bundle exec rake update"[$UPSTREAM_BRANCH]"
bundle exec rake sync_version"[$UPSTREAM_BRANCH]"
# Only consider the update's own outputs, never stray CI artifacts.
if [ -n "$(git status --porcelain -- assets lib/bootstrap/version.rb)" ]; then
echo "changed=true" >> "$GITHUB_OUTPUT"
else
echo "changed=false" >> "$GITHUB_OUTPUT"
echo "Already up to date with twbs/bootstrap@${UPSTREAM_BRANCH}."
fi

- name: Verify the stylesheets still compile
if: steps.update.outputs.changed == 'true'
run: bundle exec rake debug

- name: Commit and push
if: steps.update.outputs.changed == 'true'
run: |
sha=$(grep -oE "[0-9a-f]{40}" lib/bootstrap/version.rb | head -1)
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
git add -A -- assets lib/bootstrap/version.rb
git commit -m "Auto-update Bootstrap from twbs/bootstrap@${UPSTREAM_BRANCH} (${sha})"
git push
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ Gemfile.lock
.rvmrc
.rbenv-version

# Ignore bundler config
/.bundle
# Ignore bundler config (in the repo root and under test/gemfiles/*)
.bundle/
/vendor/cache
/vendor/bundle
tmp/
Expand Down
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,32 @@ The changelog only includes changes specific to the RubyGem.
The Bootstrap framework changes can be found in [the Releases section of twbs/bootstrap](https://github.com/twbs/bootstrap/releases).
Release announcement posts on [the official Bootstrap blog](http://blog.getbootstrap.com) contain summaries of the most noteworthy changes made in each release of Bootstrap.

# 6.0.0.alpha1

First pre-release tracking Bootstrap 6 (upstream [`v6-dev`](https://github.com/twbs/bootstrap/tree/v6-dev)). **This is an alpha; expect breaking changes.**

* **Sass module system.** Bootstrap 6 replaced `@import` with `@use`/`@forward`.
Import Bootstrap with `@use "bootstrap"` and customize variables via
`@use "bootstrap" with (...)`. See the [v5→v6 migration guide](https://github.com/twbs/bootstrap/blob/v6-dev/skills/bootstrap-v5-v6-migration/SKILL.md).
* **Dart Sass is required to compile the stylesheets.** LibSass/SassC
(`sassc-rails`) cannot compile the module system. `sassc-rails` remains a
supported Sass engine option for the gem, but Bootstrap 6's own stylesheets
will only compile under `dartsass-sprockets`, `dartsass-rails`, or
`cssbundling-rails`.
* The standalone `bootstrap-grid`, `bootstrap-reboot`, and `bootstrap-utilities`
Sass entry points were removed upstream; only `bootstrap` remains.
* **JavaScript is now ES-module only.** Bootstrap 6 removed the UMD bundle and
the `window.bootstrap` global, so the `bootstrap-sprockets` Sprockets manifest
and the `globalThis` shim are gone. Load Bootstrap via importmaps (see the
README).
* **Popper replaced by [Floating UI](https://floating-ui.com/).** The `popper_js`
runtime dependency was removed. The self-contained `bootstrap.bundle.{js,min.js}`
builds inline both `@floating-ui/dom` and `vanilla-calendar-pro`, so a single
importmap pin works with no extra dependencies (the recommended path). For
lighter-weight pinning of the non-bundled `bootstrap.{js,min.js}` or individual
component modules, a self-contained ESM build of `@floating-ui/dom` is also
vendored as `floating-ui.js`.

# 5.3.4

* Autoprefixer is now optional.
Expand Down
1 change: 0 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ source 'https://rubygems.org'
gemspec

group :development do
gem 'popper_js', '>= 1.12.3'
gem 'dartsass-sprockets'
end

Expand Down
113 changes: 71 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
# Bootstrap Ruby Gem [![CI](https://github.com/twbs/bootstrap-rubygem/actions/workflows/ci.yml/badge.svg)](https://github.com/twbs/bootstrap-rubygem/actions/workflows/ci.yml) [![Gem](https://img.shields.io/gem/v/bootstrap.svg)](https://rubygems.org/gems/bootstrap)

[Bootstrap 5][bootstrap-home] ruby gem for Ruby on Rails (*Sprockets*/*Importmaps*) and Hanami (formerly Lotus).
[Bootstrap 6][bootstrap-home] ruby gem for Ruby on Rails (*Sprockets*/*Importmaps*) and Hanami (formerly Lotus).

For Sass versions of Bootstrap 3 and 2 see [bootstrap-sass](https://github.com/twbs/bootstrap-sass) instead.

> **Bootstrap 6 (pre-release):** This is an alpha tracking the upstream
> [`v6-dev`](https://github.com/twbs/bootstrap/tree/v6-dev) branch.
> Bootstrap 6 moved its Sass to the [module system](https://sass-lang.com/documentation/at-rules/use)
> (`@use`/`@forward`), so its stylesheets require a **Dart Sass** engine to
> compile — LibSass/SassC (`sassc-rails`) cannot compile them. Its JavaScript is
> ES-module only and is loaded via importmaps. See the [CHANGELOG](CHANGELOG.md).
> For the previous stable release, use `gem 'bootstrap', '~> 5.3.8'`.

**Ruby on Rails Note**: Newer releases of Rails have added additional ways for
assets to be processed. The `twbs/bootstrap-rubygem` is for use with Importmaps
or Sprockets, but not Webpack.
Expand All @@ -21,14 +29,16 @@ Please see the appropriate guide for your environment of choice:
Add `bootstrap` to your Gemfile:

```ruby
gem 'bootstrap', '~> 5.3.8'
gem 'bootstrap', '~> 6.0.0.alpha1'
```

This gem requires a Sass engine, so make sure you have **one** of these gems in your Gemfile:
This gem requires a Sass engine, so make sure you have **one** of these gems in your Gemfile.
Bootstrap 6 stylesheets use the Sass module system, so a **Dart Sass** engine is
required to compile them — `sassc-rails` (LibSass) can no longer compile Bootstrap:
- [`dartsass-sprockets`](https://github.com/tablecheck/dartsass-sprockets): Dart Sass engine, recommended but only works for Ruby 2.6+ and Rails 5+
- [`dartsass-rails`](https://github.com/rails/dartsass-rails): Dart Sass engine, recommended for Rails projects that use Propshaft
- [`cssbundling-rails`](https://github.com/rails/cssbundling-rails): External Sass engine
- [`sassc-rails`](https://github.com/sass/sassc-rails): SassC engine, deprecated but compatible with Ruby 2.3+ and Rails 4
- [`sassc-rails`](https://github.com/sass/sassc-rails): SassC engine, deprecated and compatible with Ruby 2.3+ and Rails 4, but **cannot compile Bootstrap 6** stylesheets

Also ensure that `sprockets-rails` is at least v2.3.2.

Expand All @@ -37,14 +47,24 @@ If you are using Rails, add the `autoprefixer-rails` gem to your app and ensure

`bundle install` and restart your server to make the files available through the pipeline.

Import Bootstrap styles in `app/assets/stylesheets/application.scss`:
Import Bootstrap styles in `app/assets/stylesheets/application.scss` with `@use`
(Bootstrap 6 no longer supports `@import`):

```scss
@use "bootstrap";
```

To customize Bootstrap's variables, configure them through the `@use ... with`
rule instead of setting globals before an `@import`:

```scss
// Custom bootstrap variables must be set or imported *before* bootstrap.
@import "bootstrap";
@use "bootstrap" with (
$primary: #c0ffee,
$enable-rounded: false
);
```

The available variables can be found [here](assets/stylesheets/bootstrap/_variables.scss).
The available variables can be found in [`bootstrap/_config.scss`](assets/stylesheets/bootstrap/_config.scss).

Make sure the file has `.scss` extension (or `.sass` for Sass syntax). If you have just generated a new Rails app,
it may come with a `.css` file instead. If this file exists, it will be served instead of Sass, so rename it:
Expand All @@ -53,57 +73,68 @@ it may come with a `.css` file instead. If this file exists, it will be served i
$ mv app/assets/stylesheets/application.css app/assets/stylesheets/application.scss
```

Then, remove all the `*= require` and `*= require_tree` statements from the Sass file. Instead, use `@import` to import Sass files.
Then, remove all the `*= require` and `*= require_tree` statements from the Sass file. Instead, use `@use` to import Sass files.

Do not use `*= require` in Sass or your other stylesheets will not be able to access the Bootstrap mixins and variables.

Bootstrap JavaScript can optionally use jQuery.
If you're using Rails 5.1+, you can add the `jquery-rails` gem to your Gemfile:
### JavaScript

```ruby
gem 'jquery-rails'
```
Bootstrap 6's JavaScript is **ES-module only** — there is no UMD bundle and no
`window.bootstrap` global, so the old Sprockets `//= require bootstrap-sprockets`
concatenation is gone. Load it through **importmaps** instead.

Bootstrap tooltips and popovers depend on [popper.js] for positioning.
The `bootstrap` gem already depends on the
[popper_js](https://github.com/glebm/popper_js-rubygem) gem.
Bootstrap 6 uses [Floating UI](https://floating-ui.com/) (`@floating-ui/dom`)
for positioning tooltips, popovers, and menus, replacing Popper. A self-contained
ESM build of `@floating-ui/dom` is **vendored in this gem** as `floating-ui.js`,
so you do not need an external dependency for it.

#### Importmaps

You can pin either `bootstrap.js` or `bootstrap.min.js` in `config/importmap.rb`
as well as `popper.js`:
The simplest option is the self-contained **bundle**
(`bootstrap.bundle.min.js`), which inlines Floating UI and `vanilla-calendar-pro`,
so it needs no other pins. In `config/importmap.rb`:

```ruby
pin "bootstrap", to: "bootstrap.min.js", preload: true
pin "@popperjs/core", to: "popper.js", preload: true
pin "bootstrap", to: "bootstrap.bundle.min.js", preload: true
```

Whichever files you pin will need to be added to `config.assets.precompile`:
Then import the components you need from your application's entrypoint:

```ruby
# config/initializers/assets.rb
Rails.application.config.assets.precompile += %w(bootstrap.min.js popper.js)
```js
// app/javascript/application.js
import { Tooltip } from "bootstrap"

for (const el of document.querySelectorAll('[data-bs-toggle="tooltip"]')) {
new Tooltip(el)
}
```

#### Sprockets
The data-attribute APIs (`data-bs-toggle`, etc.) work automatically once the
module is loaded.

Add Bootstrap dependencies and Bootstrap to your `application.js`:
<details>
<summary>Lighter-weight pinning (without the bundle)</summary>

```js
//= require jquery3
//= require popper
//= require bootstrap-sprockets
If you want to avoid the bundled Floating UI / Datepicker code, pin the
non-bundled `bootstrap.min.js` together with the gem's **vendored**
`@floating-ui/dom` build:

```ruby
pin "bootstrap", to: "bootstrap.min.js", preload: true
pin "@floating-ui/dom", to: "floating-ui.js", preload: true
```

While `bootstrap-sprockets` provides individual Bootstrap components
for ease of debugging, you may alternatively require
the concatenated `bootstrap` for faster compilation:
Individual components are also available as separate modules
(e.g. `pin "bootstrap/tooltip", to: "bootstrap/tooltip.js"`) for finer-grained
pinning. The [Datepicker](https://getbootstrap.com/) component additionally
depends on [`vanilla-calendar-pro`](https://www.npmjs.com/package/vanilla-calendar-pro),
which is **not** vendored — if you use it (or the non-bundled `bootstrap.min.js`,
which imports it), pin it from a CDN:

```js
//= require jquery3
//= require popper
//= require bootstrap
```ruby
pin "vanilla-calendar-pro", to: "https://ga.jspm.io/npm:vanilla-calendar-pro@3.1.0/index.js"
```
</details>

### b. Other Ruby frameworks

Expand All @@ -123,13 +154,11 @@ By default all of Bootstrap is imported.
You can also import components explicitly. To start with a full list of modules copy
[`_bootstrap.scss`](assets/stylesheets/_bootstrap.scss) file into your assets as `_bootstrap-custom.scss`.
Then comment out components you do not want from `_bootstrap-custom`.
In the application Sass file, replace `@import 'bootstrap'` with:
In the application Sass file, replace `@use 'bootstrap'` with:

```scss
@import 'bootstrap-custom';
@use 'bootstrap-custom';
```

[bootstrap-home]: https://getbootstrap.com
[bootstrap-variables.scss]: https://github.com/twbs/bootstrap-rubygem/blob/master/templates/project/_bootstrap-variables.scss
[autoprefixer]: https://github.com/ai/autoprefixer
[popper.js]: https://popper.js.org
19 changes: 18 additions & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ task :debug do
require './lib/bootstrap'
require 'term/ansicolor'
path = Bootstrap.stylesheets_path
%w(_bootstrap _bootstrap-reboot _bootstrap-grid).each do |file|
# Bootstrap 6 exposes a single `bootstrap` entry point.
%w(_bootstrap).each do |file|
filename = "#{path}/#{file}.scss"
css = if defined?(SassC::Engine)
SassC::Engine.new(File.read(filename), filename: filename, syntax: :scss).render
Expand All @@ -77,6 +78,22 @@ task :update, :branch do |t, args|
Updater.new(branch: args[:branch]).update_bootstrap
end

desc 'Update only bootstrap stylesheets from upstream (leaves JS untouched)'
task :update_scss, :branch do |t, args|
require './tasks/updater'
Updater.new(branch: args[:branch], skip_js: true).update_bootstrap
end

desc 'Sync the gem VERSION to the upstream Bootstrap package.json version'
task :sync_version, :branch do |t, args|
require './tasks/updater'
# npm prerelease versions (e.g. 6.0.0-alpha1) map to RubyGems (6.0.0.alpha1).
gem_version = Updater.new(branch: args[:branch]).upstream_version.sub('-', '.')
path = 'lib/bootstrap/version.rb'
File.write(path, File.read(path).sub(/VERSION\s*=\s*'[^']*'/, "VERSION = '#{gem_version}'"))
$stderr.puts "VERSION set to #{gem_version}"
end

desc 'Start a dummy Rails app server'
task :rails_server do
require 'rack'
Expand Down
6 changes: 0 additions & 6 deletions assets/javascripts/bootstrap-global-this-define.js

This file was deleted.

2 changes: 0 additions & 2 deletions assets/javascripts/bootstrap-global-this-undefine.js

This file was deleted.

28 changes: 0 additions & 28 deletions assets/javascripts/bootstrap-sprockets.js

This file was deleted.

Loading