Rails 关于前端的思考和疑惑

rux_9527 · 2022年01月04日 · 最后由 rux_9527 回复于 2022年01月04日 · 533 次阅读

新人轻喷!😂 和大家一样, 我很喜欢 Rails 框架.! 但我不太欣赏这种前端深度融合模式!

总感觉深度融合前端,在一定程度上阻碍了框架的更流行?!!

2011 年 8 月 31 日, Rails 3.1 首次携 Asset Pipeline 机制发布, 该组件主要能力是针对静态资源: 编译、打包、哈希等, 是当时比较领先的设计! 虽说如此, 但是据我了解, 这个机制需要第三方前端库做适配, 就是说要先修改再用 gem 包封装, 作为用户者就必须得找第三方对应的 gem. 这是不是增加了入门坡度? 原谅我不是太能理解, 好在当时前端界打包还没成型, 框架给大家带来了便利也提升了高度. 像今天这样前端大统一, Rails 不得不重新审视组装自己的前端组件, 某种程度上它阻碍了自身流行.

Asset Pipeline 在发布之前 Node 和 Npm 已经问世, 2 年半以后 Webpack 也发布于众. 随着 ES6 模块化的普及和 http/2 规范出台, 前端形势一片大好. Asset Pipeline 不再具有明显优势, 反而劣势突出. 如今前端社区默认的打包工具是 webpack, Rails6 就将其集成进来制作了 webpacker. 抱歉, Rails7 中前端其他打包方案还不很了解, 所以我针对 Rails6 梳理了些问题:

在这之前, 我想先描述一下我对前端的理解思路:

抛出问题: webpack 是前端打包工具, 而 npm 安装的包又是运行在 node 上的 js 包。 那么: npm 安装的包是不是经过 webpack 打包而来的?比如 bootstrap、JQuery、vue 等。

是也不是???! 理解关键点是:

a. webpack到底有什么功能 ==> 编译、压缩、打包
b. npm到底可以安装什么包 ==> node包还是browser上的库

前提: ES6 和 Node 是两个层面的东西: 前者是规范,后者是对前者的实现! 在 ES6 之前, Js 是不支持模块化开发的, 现代化 Js 却都使用模块化开发方式!

1)说不是。

Node 是实现运行时, 它支持模块化运行方式, 如果 npm 安装的包运行在 node 上, 那它不需要做编译转化! 比如常见的 vue 框架, 提供命令行; 或者使用 node 开发的服务器后台程序, 都是如此! 这样看: npm 安装的包不是经过 webpack 打包而来的! 事实上真是这样吗 ??

2) 说是。

目前浏览器不支持 JS 模块化, 像这样的代码需要被编译转化, 这个功能就被实现到 webpack 里. 实际上, npm 安装包未必只能安装 js 代码, 比如 bootstrap; 即使是 js 代码, 也未必是给 node 运行的, 比如 JQuery, 就是给 browser 准备的 那它们就有必要被编译转化, 所以也可以说成: npm 安装的包是经过 webpack 打包而来的

按照常识做个推算:

A) 简术下 Linux 操作系统: 它由 linus Torvalds 在 1991 年开发出来的 Kernel、初始化子系统 systemd、终端 shell 和互联网其他 基础服务程序 (比如 bind) 组成. 公布的完整系统分成两大阵营: RedHat 和 Debian, 它们的组成基本一致, 区别是包管理器: yum(rpm) 和 apt-get(dpkg)!!! 这种包不论是哪种安装器, 也不论是哪种开发语言, 都必须满足系统目录使用规范, 才能被正确使用

B) 系统上编译安装 Ruby 安装在 /usr/local/ruby 目录下; 这样: 我们会得到解释执行器程序, 和它自己的包管理工具 gem! 那 gem 安装的软件包将是: 使用'ruby'代码完成的 “完整小工具或者框架”, Rails、devise 等就是典型代表!
这些包还可以是 DB 驱动、前端包, 必须满足 ruby 目录使用规范,才能被正确使用

C) 系统上编译安装 Python 安装在 /usr/local/python 目录下; 这样: 我们会得到解释执行器程序, 和它自己的包管理工具 pip! 那 pip 安装的软件包将是: 使用'python'代码完成的 “完整小工具或者框架”, Django、ipython 等就是典型代表! 这些包还可以是 DB 驱动, 必须满足 python 目录使用规范,才能被正确使用

D) 系统上编译安装 node 安装在 /usr/local/node 目录下; 这样: 我们会得到解释执行器程序,和它自己的包管理工具 npm! 那 npm 安装的软件包将是: 使用'JS'代码完成的 “完整小工具或者框架”, Jquery、vue 等就是典型代表! 这些包分为全局和局部, 全局包必须满足 node 目录使用规范, 才能被正确使用, 另外 yarn 是 npm 的替代品, 安装的东西是一样的

事实上, gem/pip 安装的包既有命令行, 又有框架; 整体上说它们还是跑在虚拟机运行时上; node 似乎不满足这种规范, npm 安装的包有的可以跑在 node 上, 比如 vue; 有的可以跑在浏览器上, 比如 jQuery

请教的问题是: 假如说, 有一个请求到达 Rails 系统

  1. 路由组件先收到这个请求,并发送到 controller#action 动作上
  2. 这个 controller 可以指定 layout 布局, 或者在 action 里使用 render :layout => 指定布局
  3. 布局文件默认是指向 app/view/layout/application.html.erb 或者该目录的其他文件
  4. 文件里有两条指令 stylesheet_link_tag 和 javascript_pack_tag, 他们的参数都是 application
4_1. stylesheet_link_tag => app/assets/stylesheets/application.css (scss) 

4_2. javascript_pack_tag => app/javascript/packs/application.js (config/webpacker.yml)

application.js 文件里使用 import "bootstrap", 默认是 app/node_modules/bootstrap

1) 如果使用 yarn add xxxx 其他的js库,是不是意味着 import xxxx 就可以找到 ?
2) 如果自己编写的 yyyy.js 放在 app/javascript/packs, 应该写 import yyyy 嘛 ?
3) bootstrap 依赖 jquery,导入了bootstrap是不是不用在单独导入 jquery ?
4) 这个目录 app/javascript/channels 是做什么用的呢 ?

css 文件里使用 @import "bootstrap/dist/css/bootstrap"; 默认是 app/node_modules/bootstrap/dist/css/bootstrap.css

1) 如果使用 yarn add zzzz 其他的css库,是不是代表着 @import "path_zzzz" 必须对应到相应的css文件 ?
2) 这个目录 app/assets/stylesheets 默认情况下会创建针对控制器Controller的css文件, 哪里制定它的呢 ?

官网指南看上去还没整明白,望大神指点迷津,有没有 6 版的中文手册之类的...

问: "总感觉深度融合前端,在一定程度上阻碍了框架的更流行?!!"

答: 一定范围内, 是的, rails 想做的事情太多, 但是大多数人的耐心是有限的, 或者职责是有限的,只不过对于创业者来说, rails 提供了一揽子解决方案。

问: “抛出问题: webpack 是前端打包工具, 而 npm 安装的包又是运行在 node 上的 js 包。 那么: npm 安装的包是不是经过 webpack 打包而来的?比如 bootstrap、JQuery、vue 等。”

答: webpack 是一种打包方式, npm 包不依赖 webpack, webpack 最本质的目的是为了处理不同 js 文件的互相引用问题。webpack 还有很多前辈或者同辈也在解决这个问题,例如 grunt. gulp 等。至于裁剪, 压缩, 顺带解 css 啥的, 是他的附带业务, 不是主业。

其他的内容 恕我语文不太好, 没明白你的意思。

Rails 的这一套前后端一把梭曾经辉煌过,不过当下前端已经完全不需要 Rails 了,至于后端,Java 恐怕永远是老大。即便让我写一套全栈的,那也是选择 Node.js 写后端

Rails7 提供了可选前端方案,官方推出的 Hotwire 生态还是白板,轮子基本需要自己撸。所以目前还是 Rails6 时代的 Webpacker 是比较成熟好用。webpacker 和 rails 结合一般是 2 种方法:

1 使用 React/vue/Angular 接管前端路由。rails 只提供 API。

好处:几乎可以利用全部前端生态。

弊端:需要管理前后端 2 套路由,增加心智维护成本和开发量,很多简单的页面本来 render 一下的事,就需要分别写一个前端页面 +1 个 API。而且两套路由,在做权限管理的时候就会非常抓狂。

2 使用 Rails 的路由 + 部分 React/Vue 的页面渲染 +Turbolinks/Turbo(可选)

好处:

  • 灵活自由
  • 一套 restful 路由非常整洁。
  • 简单的展示页面/列表不用去写前端 js 部分。

弊端:

  • 需要自己处理 Turbolinks/Turbo 的一些坑,当然可以选择禁用。
  • 前端生态圈很多轮子不能开箱即用了,需要自己配置折腾一下。甚至有些根本不能用。
  • 需要维护 2 套 view 文件,其中 rails 那套可能就一行代码,但是必须写,很烦人。

回答问题

1) 如果使用 yarn add xxxx 其他的 js 库,是不是意味着 import xxxx 就可以找到 ?

是的

2) 如果自己编写的 yyyy.js 放在 app/javascript/packs, 应该写 import yyyy 嘛 ?

写相对路径

import xxx from './yyyy'

3) bootstrap 依赖 jquery,导入了 bootstrap 是不是不用在单独导入 jquery ?

把 jquery 注册到全局就行了,你参考下这个 config/webpack/environment.js ,VUE+jquery 的

const { environment } = require('@rails/webpacker')
const { VueLoaderPlugin } = require('vue-loader')
const vue = require('./loaders/vue')
const webpack = require('webpack')

environment.plugins.append('Provide',
    new webpack.ProvidePlugin({
        $: 'jquery',
        jQuery: 'jquery',
        Popper: ['popper.js', 'default'] 
    })
)
environment.plugins.prepend('VueLoaderPlugin', new VueLoaderPlugin())
environment.loaders.prepend('vue', vue)
module.exports = environment

4) 这个目录 app/javascript/channels 是做什么用的呢 ?

action_cable组件的默认 js

可以用 rails g channel 生成一个看看里面有什么,主要用于实时通讯,比如聊天室。服务端依赖 redis。


1) 如果使用 yarn add zzzz 其他的 css 库,是不是代表着 @import "path_zzzz" 必须对应到相应的 css 文件 ?

貌似是的

2) 这个目录 app/assets/stylesheets 默认情况下会创建针对控制器 Controller 的 css 文件, 哪里制定它的呢 ?

其实并不需要定制,全部写到 javascript/stylesheets/application.scss 里就行了,因为 require 进来的文件似乎有加载顺序的问题。 如果你用的 vue 或者 react,那你的样式最好遵循前端框架约定。

官网指南看上去还没整明白,望大神指点迷津,有没有 6 版的中文手册之类的...

目前是没有的中文官网指南还是 Rails5 的,不过足够用了。

Rails 是个 MVC 框架,目前 V 还是用前端生态里的实践方案会比较好,Rails 提供的默认前端解决方案并不是很现代,过于强调复用,会导致 view 碎片化。而前端的 C 层解决方案又是堆 shi 山的副产物,而且并不能让后端省去 C 层开发,而导致前后端分裂。所以 Rails 官网指南重点学习 M 和 C 就行了。其他的完全不看都可以,像 mailer action_cable 这些并不是一个 Web Application 必须的。

M 层和 C 层 Rails5 到 Rails7 几乎没有什么变化。而且 Rails 精髓也就在 M 和 C。

jicheng1014 回复

😃 非常感谢大神回复!列举了 ruby 下 gem、python 下 pip、node 下 npm,是想证明 npm 安装的包和 webpack 没有一毛钱关系。而 Rails6 引入 webpack 打包静态资源,却要用 npm 方式去安装第三方依赖包,主要是想搞明白它们的关系!至于剩下的问题无非是:如何使用问题?在 webpack 下如何引入已有的前端库,如何引入自实现的文件?研究原理不必要,至少会用嘛。还是很感谢

hxh1246996371 回复

😔 😔 😔 终究还是上晚了车!基于 rails 这一套有没有可能出现新的框架,这种元编程能力真是又爱又恨啊

nine 回复

👍 满分大神💯,多谢指教,我去折腾一下

npmyarn 安装依赖的行为理解成下载 围绕 JavaScript 的文件到本地会不会更容易理解一些呢?

举个简单的例子,当我们执行

npm i -g @vue/cli

下载的是一个脚手架工具;

执行

npm i bootstrap

下载的是一套 UI 样式库;

更多的时候,我们下载下来的东西可能千奇百怪,可能是 JavaScript 文件,可能是 css 文件,甚至还可能有 cpp 文件(参考 node-sass)……

所以其实打不打包和 npm/yarn 并没啥关系,它取决于作者出于什么样的考虑来实现这个包,如果它只是使用在 NodeJS 环境,打不打包并不会影响正常使用;但如果在浏览器端就可能需要考虑各种适配情况,例如新的 ECMAScript 语法等,通过构建工具优雅降级并压缩非常重要;又例如命令行工具,或许需要考虑的只是各操作系统之间的兼容问题,因此也就没有一定要打包的必要了。

yuchiXiong 回复

嗯嗯,正对点上了!这样理解顺畅许多!npm/yarn 提供的是包下载能力!至于下载的包有没有经过 webpack 打包处理,那是作者另一个维度考虑了💡

需要 登录 后方可回复, 如果你还没有账号请 注册新账号