文章目录
在这篇文章中我们会介绍 Webpacker、 Yarn和 Sprockets
.
和以往的版本不同,6之前的js脚本存放目录是app/assets/javascripts
,但是到了6,官方推荐的js脚本存放位置是app/javascript
目录
在这篇文章中,我会一步一步地介绍如何将bootstrap和FontAwesome 5加入到rails 6项目中
NPM这个没啥好介绍的,他就是node.js的包管理工具,就像python的pip,ruby的gem和php的composer
npm install bootstrap
npm会自动将下载下来的包存放到node_modules目录中,并在package.json中维护一个列表
{
"name": "demo",
"private": true,
"dependencies": {
"@rails/actioncable": "^6.0.0",
"@rails/activestorage": "^6.0.0",
"@rails/ujs": "^6.0.0",
"@rails/webpacker": "4.2.2",
"turbolinks": "^5.2.0",
"markdown": "0.5.0"
},
"version": "0.1.0",
"devDependencies": {
"webpack-dev-server": "^3.10.3"
}
}
Yarn
yarn也是js的包管理工具,但是它比npm更强大
yarn会根据package.json文件中的内容自动更新我们所需要的包,你可以在yarn.lock
文件中锁定我们的包版本,这样yarn就不会自动更新他们了
在rails 6中,如果我们需要一个js库,我们只需要执行yarn add package_name
即可
js的新标准,他提供了一系列新的特性,这里暂且不表
Babel因为大部分浏览器都还不支持ES6,所以我们需要Babel将ES6编译成ES5,Babel就是这个负责转换ES6到ES5的工具
Webpack现在我们有了Babel和Yarn和他们的配置文件,现在我们需要一个工具使得这些东西能够自动执行和配置,以此让我们更在专注于代码的编写
Webpack将会帮助我们编译assets,webpack会把他们编译成适当的插件,然后这些插件又会被我们的程序使用进行各种处理工作
以下是webpack可以帮我们做到的:
- 处理ES6代码
- 使用babel-loader插件使得Babel自动将ES6代码转换为ES5代码
- 将输出结果打包到一个我们可以将其包含到html dom中的js文件如下所示:
<script type="text/javascript" src="path-to-es5-javascript-pack.js"></script>
Webpacker
注意不要将其和Webpack混淆
Webpacker是一个gem,他将webpack包含进我们的rails应用中。它自身带有一些初始配置(足够我们起步),这样我们就可以不用操心配置的问题,直接开始编写实际的代码
Webpacker的默认配置:
app/javascript/packs
目录应该包含你的js代码- 你可以在你的视图中使用如下方式包含js代码
javascrit_pack_tag '<pack_name>'
举个例子:
<%= javascript_pack_tag 'my_app' %>
对应的html代码就是:src="app/javascript/packs/my_app.js")
在文章的最后我将会讲解所有的这些到底是如何工作的,不过在此之前我们先讲一下Sprockets
有的读者肯能会问,既然js已经转移到了app/javascript
目录,那么css文件呢?
这一点我们可以通过查看config/webpacker.yml
文件来解答:
# Extract and emit a css file
extract_css: false
通过注释我们可以看到,webpacker是可以做到将css也放在新的位置而不是app/assets/stylesheets
中,而且webpacker也提供了对应的引用标签stylesheet_pack_tag
,但是我们有看到extract_css
的值是false
,可以得知默认css的提取是关闭的,所以我们依然可以使用Sprockets
,使用旧目录app/assets/stylesheets
另外一点值得注意的地方是,你可能会认为在运行rails assets:precompile
时,rails只会预编译app/assets
中的文件,但是实际上rails会将app/javascrit
和Sprockets的app/assets
中的文件都进行预编译
正如Webpack,Sprockets也是一个资源管道,这意味着她也是负责处理资源文件(js、css、images、字体文件等等),将它们转换为目标格式
在rails 6中webpack(er)代替了Sprockets成为了在rails应用中编写js的新标准。尽管如此,Sprockets仍然是css文件的默认处理方式
在rails 5,Sprockets 3中,我们需要将assets清单添加到config.assets.precompile
文件中
而在rails 6,Sprockets 4中,我们则需要将assets清单写到app/assets/config/manifest.js
中
如果你想向Sprockets添加资源,你要完成以下事情
- 讲你的css文件放到
app/assets/stylesheets/
目录下 - 确保你的
app/assets/config/manifest.js
对stylesheet_link_tag
或者link_tree
、link_directory
、link
语句是可用的 - 使
stylesheet_link_tag
将其引入到你的视图中<%= stylesheet_link_tag 'my_makeup' %>
当然,也有其他的引入方式
不要以使用Sprockets的方式使用Webpacker理解下面的内容对你来说将是很重要的,它可以帮你省去好几个小时的时间
在编译模块这方面,Webpack和Sprockets是有很大的差异的
在rails 6中,你所编写的js都被模块化了,存放在不同的命名空间下,不能直接被全局访问,你需要先导入模块,然后方可调用相应的方法,看一下下面的例子你就明白了
这是使用Sprockets的写法app/assets/javascripts/hello.js
内容如下:
function hello(name) {
console.log("Hello " + name + "!");
}
app/assets/javascripts/user_greeting.js
内容如下
function greet_user(last_name, first_name) {
hello(last_name + " " + first_name);
}
视图app/views/my_controller/index.html.erb
内容如下:
<%= javascript_link_tag 'hello' %>
<%= javascript_link_tag 'user_greeting' %>
<button onclick="greet_user('Dire', 'Straits')">Hey!</button>
上面的例子很好理解,没有什么特殊的地方
但是在Webpacker中怎么写呢
如果你认为只需要直接将上面两个js文件移动到app/javascript/packs
那你就大错特错了
因为hello()
会被编译成ES6 模块,user_greeting()
也一样,尽管包含这两个文件的相应的编译后的js文件你被包含了进来,其实hello方法也是不存在的
那么我们应该怎么做呢?
app/javascript/packs/hello.js
:
export function hello(name) {
console.log("Hello " + name + "!");
}
app/javascript/packs/user_greeting.js
:
import { hello } from './hello';
function greet_user(last_name, first_name) {
hello(last_name + " " + first_name);
}
app/views/my_controller/index.html.erb
:
<%= javascript_pack_tag 'user_greeting' %>
<button onclick="greet_user('Dire', 'Straits')">Hey!</button>
这样就行了吗?
大师是否定的,因为greet_user
是不可被访问到的,一旦被编译,它就被隐藏到了一个模块中
最终我们找到了这一章节的重点:
- Sprockets:视图可以直接和js文件进行交互,比如调用js中的方法和变量等等等
- webpack:视图没办法直接访问js
那么我们到底该怎么做呢?
请看下面的
我们使用jquery
举例子:
import $ from 'jquery';
import { hello } from './hello';
function greet_user(last_name, first_name) {
hello(last_name + " " + first_name);
}
$(document).ready(function() {
$('button#greet-user-button').on(
'click',
function() {
greet_user('Dire', 'Strait');
}
);
});
/* Or the ES6 version for this: */
$(() =>
$('button#greet-user-button').on('click', () => greet_user('Dire', 'Strait'))
);
app/views/my_controller/index.html.erb
:
<%= javascript_pack_tag 'user_greeting' %>
<button id="greet-user-button">Hey!</button>
我们使用<%= javascript_pack_tag 'user_greeting' %>
引入app/javascript/packs/user_greeting.js
可以看到我们是监听事件,而不是直接在视图中调用js中的function