Rails 关于前端的思考和疑惑

rux_9527 · January 04, 2022 · Last by mikasa replied at September 18, 2023 · 1276 hits

新人轻喷!😂 和大家一样,我很喜欢 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。

Reply to jicheng1014

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

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

Reply to nine

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

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

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

npm i -g @vue/cli

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

执行

npm i bootstrap

下载的是一套 UI 样式库;

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

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

Reply to yuchiXiong

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

是的,npm 包确实可以通过 Webpack 进行打包。Webpack fnf 是一种流行的 JavaScript 模块捆绑器,它可以获取各种模块(包括通过 npm 安装的模块),并将它们捆绑在一起以在 Web 应用程序中使用。

You need to Sign in before reply, if you don't have an account, please Sign up first.