Rails 6.0 发布已经有一段时间了,之前没有什么项目可以练手,最近总算遇到可以使用 Rails 6 开发的场景了。Rails 6 中新增了一些功能和特性,有一些内容官方文档里并没有写的很具体,所以在摸索的过程中也遇到了一些坑点。这里以一个新工程从头到尾的构建,来简单记录在 Rails6 中使用 jQuery 和 Bootstrap 的过程。希望能够给新来的同学做个参考。
编程和码字的水平有限,如有错漏敬请指教,也请多包涵!下面就开始吧。
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
这里新建一个项目“TestApp”,并在其中建立控制器“Test”和测试方法“test”:
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 代码:
<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:
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
此时应用已经创建成功。
这里采用 yarn 作为 Javascript 包管理器。在 TestApp 目录中运行bin/yarn
,如果出现以下内容,说明 yarn 没有安装:
test@debian:~/TestApp$bin/yarn
Yarn executable was not detected in the system.
Download Yarn at https://yarnpkg.com/en/docs/install
安装方法在这里,以当前使用的 Debian 10 为例,安装的方法是:
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 包:
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,不装的话会报依赖错误,所以安装一下:
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目录,所需的前端库已经添加好了:
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$
跟 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的话,那么采用如下方式来引用:
/*
* 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 是否已经引入成功:
<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 已经成功引入了。
继续修改app/javascript/packs/application.js,添加用于测试 jQuery 的代码:
// 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页面,发现添加的代码无法执行,控制台中有报错:
ReferenceError: $ is not defined
application.js:21
这是因为 jQuery 库也需要引入一下,但是引入的方式有些不同,并不是在页面中直接引入,而是需要在config/webpack/environment.js中添加以下引入代码:
var webpack = require('webpack');
environment.plugins.append( 'Provide',
new webpack.ProvidePlugin({
$: 'jquery',
})
)
通过声明一个全局的导出,就可以在全局的 JS 代码文件中使用"$"符号了。
刷新并再次访问,代码能够运行,控制台也没有再报错,说明 jQuery 已经成功集成:
另一种方法
还有一种方法是通过在 JS 文件按中使用import $ from 'jquery'
来使"$"符生效,但是这样比较繁琐,需要在每个 JS 文件中出现,所以不再介绍了,当然,也提供一下详细的代码参考
// 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());
});
});
在网上主要参考了这篇文章。Rails 6 中的变化还是挺大的,不知道 webpack 会不会真的成为 Rails 的未来,感觉之前使用 coffee script 来写 JS 的同学不是很多,但是我倒是已经非常习惯于使用它来开发前端功能了。
但是想必 Rails 的先驱们有着他们更成熟的考虑吧,那就一起继续探索好了。
本文同步发表在我的博客: 在 Rails6 中使用 jQuery 和 bootstrap( Using jQuery and Bootstrap on Rails 6 )