#Bootstrap

0x00 前言

Rails 6.0 发布已经有一段时间了,之前没有什么项目可以练手,最近总算遇到可以使用Rails 6开发的场景了。Rails 6中新增了一些功能和特性,有一些内容官方文档里并没有写的很具体,所以在摸索的过程中也遇到了一些坑点。这里以一个新工程从头到尾的构建,来简单记录在Rails6中使用jQuery和Bootstrap的过程。希望能够给新来的同学做个参考。

编程和码字的水平有限,如有错漏敬请指教,也请多包涵!下面就开始吧。

0x01 环境准备

  • 操作系统: Debian 10 ( 4.19.0-8-amd64 )
  • Ruby版本: ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-linux]
  • Rails版本: Rails 6.0.2.1
1
2
3
4
5
6
7
test@debian:~$uname -a
Linux debian 4.19.0-8-amd64 #1 SMP Debian 4.19.98-1 (2020-01-26) x86_64 GNU/Linux
test@debian:~$ruby -v
ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-linux]
test@debian:~$rails -v
Rails 6.0.2.1

0x02 创建项目

这里新建一个项目“TestApp”,并在其中建立控制器“Test”和测试方法“test”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
test@debian:~$rails new TestApp
create
create README.md
create Rakefile
create .ruby-version
create config.ru
create .gitignore
create Gemfile
...
├─ [email protected]
├─ [email protected]
└─ [email protected]
Done in 59.74s.
Webpacker successfully installed 🎉 🍰
test@debian:~/TestApp$rails g controller Test test --no-stylesheets
Running via Spring preloader in process 22413
create app/controllers/test_controller.rb
route get 'test/test'
invoke erb
create app/views/test
create app/views/test/test.html.erb
invoke test_unit
create test/controllers/test_controller_test.rb
invoke helper
create app/helpers/test_helper.rb
invoke test_unit
invoke assets
invoke scss
test@debian:~$

创建好之后,修改test页面,添加一个表单和按钮,用于稍后测试Bootstrap。(在执行创建控制器和方法的命令后,Rails已经为我们自动添加了到Test控制器test方法的路由,所以不需要我们再新增路由。)

app/views/test/test.html.erb 代码:

1
2
3
4
5
6
7
<h1>Test#test</h1>
<p>Find me in app/views/test/test.html.erb</p>

<form>
<input id="test" type="text"/>
<button id="test_btn">点我</button>
</form>

启动Rails服务,访问http://localhost:3000/test/test:

1
2
3
4
5
6
7
8
9
10
11
test@debian:~/TestApp$rails s
=> Booting Puma
=> Rails 6.0.2.1 application starting in development
=> Run `rails server --help` for more startup options
Puma starting in single mode...
* Version 4.3.1 (ruby 2.6.5-p114), codename: Mysterious Traveller
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://127.0.0.1:3000
* Listening on tcp://[::1]:3000
Use Ctrl-C to stop

此时应用已经创建成功。

0x03 添加jQuery和Bootstrap库

这里采用yarn作为Javascript包管理器。在TestApp目录中运行bin/yarn,如果出现以下内容,说明yarn没有安装:

1
2
3
test@debian:~/TestApp$bin/yarn
Yarn executable was not detected in the system.
Download Yarn at https://yarnpkg.com/en/docs/install

安装方法在这里, 以当前使用的Debian 10为例,安装的方法是:

1
2
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list

安装好yarn之后,就可以用yarn添加jQuery包和Bootstrap包:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
test@debian:~/TestApp$yarn add jquery 
yarn add v1.21.1
[1/4] Resolving packages...
[2/4] Fetching packages...
info [email protected]: The platform "linux" is incompatible with this module.
info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
warning " > [email protected]" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
warning "webpack-dev-server > [email protected]" has unmet peer dependency "webpack@^4.0.0".
[4/4] Building fresh packages...

success Saved lockfile.
success Saved 1 new dependency.
info Direct dependencies
└─ [email protected]
info All dependencies
└─ [email protected]
Done in 9.98s.
test@debian:~/TestApp$yarn add bootstrap
yarn add v1.21.1
[1/4] Resolving packages...
[2/4] Fetching packages...
info [email protected]: The platform "linux" is incompatible with this module.
info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
warning " > [email protected]" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
warning "webpack-dev-server > [email protected]" has unmet peer dependency "webpack@^4.0.0".
warning " > [email protected]" has unmet peer dependency "popper.js@^1.16.0".
[4/4] Building fresh packages...

success Saved lockfile.
success Saved 1 new dependency.
info Direct dependencies
└─ [email protected]
info All dependencies
└─ [email protected]
Done in 13.33s.

由于Bootstrap还需要基于popper.js,不装的话会报依赖错误,所以安装一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
test@debian:~/TestApp$yarn add popper.js
yarn add v1.21.1
[1/4] Resolving packages...
warning [email protected]: You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1
[2/4] Fetching packages...
info [email protected]: The platform "linux" is incompatible with this module.
info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
warning " > [email protected]" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
warning "webpack-dev-server > [email protected]" has unmet peer dependency "webpack@^4.0.0".
[4/4] Building fresh packages...
success Saved lockfile.
success Saved 1 new dependency.
info Direct dependencies
└─ [email protected]
info All dependencies
└─ [email protected]
Done in 11.78s.

安装的执行结果:

因为众所周知的原因,网速慢的同学就尴尬了,这里可能要等很久,所以你需要选一个科学一点的方式。

此时查看TestApp/node_modules目录,所需的前端库已经添加好了:

1
2
3
4
5
6
7
test@debian:~/TestApp$ls node_modules/jquery/
AUTHORS.txt bower.json dist external LICENSE.txt package.json README.md src
test@debian:~/TestApp$ls node_modules/bootstrap/
dist js LICENSE package.json README.md scss
test@debian:~/TestApp$ls node_modules/popper.js/
dist index.d.ts index.js.flow package.json README.md src
test@debian:~/TestApp$

0x04 使用Bootstrap

跟Rails5有所不同的是,Rails6采用webpack打包的方式,把需要打包的资源统一放在一个文件里(Rails6之前是采用Gemfile的方式引入第三方库,再通过Asset Pipeline汇聚)。

于是在安装好所需的前端库之后,就需要在app/javascript/packs/application.js中先引用它:

以Bootstrap为例,在其中添加import 'bootstrap'引入语句:

与此同时还需要在application.scss中引入Bootstrap的CSS样式表:

app/assets/stylesheets/application.scss文件中添加@import "bootstrap/dist/css/bootstrap";


2020/05/28 Patch

纠个错,如果想要通过@import "bootstrap/dist/css/bootstrap";的方式引用bootstrap相关的CSS,需要把app/assets/stylesheets/application.css文件重命名为app/assets/stylesheets/application.scss
如果直接使用app/assets/stylesheets/application.css的话,那么采用如下方式来引用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
* File: app/assets/stylesheets/application.css
* This is a manifest file that'll be compiled into application.css, which will include all the files
* listed below.
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
* vendor/assets/stylesheets directory can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
* files in this directory. Styles in this file should be added after the last require_* statement.
* It is generally better to create a new file per style scope.
*
*= require bootstrap/dist/css/bootstrap
*= require_tree .
*= require_self
*/

Ending Patch


接着继续修改app/views/test/test.html.erb文件中的代码,添加相应的CSS类来测试Bootstrap是否已经引入成功:

1
2
3
4
5
6
7
8
9
<h1>Test#test</h1>
<p>Find me in app/views/test/test.html.erb</p>

<form>
<div class="form-group">
<input id="test" type="text" class="form-control"/>
<button id="test_btn" class="btn btn-success">点我</button>
</div>
</form>

启动应用,再次访问测试页面:

虽然界面有点丑,但是从渲染效果来看,Bootstrap已经成功引入了。

0x05 使用jQuery

继续修改app/javascript/packs/application.js,添加用于测试jQuery的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.

require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")


// Uncomment to copy all static images under ../images to the output folder and reference
// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>)
// or the `imagePath` JavaScript helper below.
//
// const images = require.context('../images', true)
// const imagePath = (name) => images(name, true)

import 'bootstrap'

$(document).on('turbolinks:load', function(){
$("#test_btn").click(function(){
alert($("#test").val());
});
});

保存并运行,刷新https://localhost:3000/test/test页面,发现添加的代码无法执行,控制台中有报错:

1
2
ReferenceError: $ is not defined 
application.js:21

这是因为jQuery库也需要引入一下,但是引入的方式有些不同,并不是在页面中直接引入,而是需要在config/webpack/environment.js中添加以下引入代码:

1
2
3
4
5
6
var webpack = require('webpack');
environment.plugins.append( 'Provide',
new webpack.ProvidePlugin({
$: 'jquery',
})
)

通过声明一个全局的导出,就可以在全局的JS代码文件中使用”$”符号了。

刷新并再次访问,代码能够运行,控制台也没有再报错,说明jQuery已经成功集成:

另一种方法

还有一种方法是通过在JS文件按中使用import $ from 'jquery'来使”$”符生效,但是这样比较繁琐,需要在每个JS文件中出现,所以不再介绍了,当然,也提供一下详细的代码参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.

require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")


// Uncomment to copy all static images under ../images to the output folder and reference
// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>)
// or the `imagePath` JavaScript helper below.
//
// const images = require.context('../images', true)
// const imagePath = (name) => images(name, true)

import 'bootstrap'
import $ from 'jquery' // 在每个JS文件中加上这一行,也可以替代声明全局变量。

$(document).on('turbolinks:load', function(){
$("#test_btn").click(function(){
alert($("#test").val());
});
});

0x06 总结

在网上主要参考了这篇文章。Rails 6中的变化还是挺大的,不知道webpack会不会真的成为Rails的未来,感觉之前使用coffee script来写JS的同学不是很多,但是我倒是已经非常习惯于使用它来开发前端功能了。

但是想必Rails的先驱们有着他们更成熟的考虑吧,那就一起继续探索好了。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×