解决Ruby ERB模板中JS美化难题:从混乱到优雅的完整指南
【免费下载链接】js-beautify Beautifier for javascript 项目地址: https://gitcode.com/gh_mirrors/js/js-beautify
引言:你还在为ERB模板中的JS代码头疼吗?
作为Ruby on Rails开发者,你是否经常面临这样的困境:ERB模板中嵌入的JavaScript代码格式混乱不堪,手动调整既耗时又容易出错,而直接使用格式化工具又会破坏ERB标签结构?本文将为你展示如何利用js-beautify工具,通过巧妙的配置和自定义处理,轻松解决这一痛点。
读完本文后,你将能够:
- 理解ERB模板中JS美化的核心挑战
- 掌握js-beautify的高级配置技巧
- 实现ERB模板中JavaScript代码的自动格式化
- 构建自定义的ERB-JS美化工作流
- 解决常见的格式化冲突问题
ERB模板中JS美化的核心挑战
ERB(Embedded Ruby)模板允许开发者在HTML中嵌入Ruby代码,这为动态页面生成提供了极大便利。然而,当在ERB中嵌入JavaScript代码时,就产生了特殊的格式化挑战:
<script>
<% if current_user.admin? %>
$(document).ready(function(){
$('#admin-panel').show();
<% else %>
$(document).ready(function(){
$('#user-panel').show();
<% end %>
});
</script>
上述代码存在多个问题:缩进不一致、Ruby条件与JS逻辑混合、括号匹配困难。直接使用标准JS格式化工具会破坏ERB标签,而忽略格式化又会导致代码可维护性急剧下降。
ERB与JS混合代码的结构特点
通过分析ERB模板的结构,我们可以总结出三个关键挑战:
- 语法边界模糊:ERB标签
<% %>与JS代码交织,形成复杂的语法边界 - 上下文切换频繁:Ruby逻辑与JavaScript逻辑在同一文件中频繁切换
- 缩进层级冲突:Ruby代码缩进与JavaScript缩进规则可能不一致
js-beautify作为一款功能强大的代码格式化工具,其核心优势在于能够处理复杂的代码结构并提供高度可定制的格式化规则。通过深入了解其工作原理,我们可以找到解决ERB-JS格式化难题的方案。
js-beautify工作原理解析
核心架构
js-beautify采用模块化设计,主要包含三个核心组件:
代码美化流程
js-beautify的工作流程可以分为四个主要步骤:
- 词法分析:将输入代码分解为Token序列
- 语法模式识别:识别代码结构和上下文模式
- 格式化规则应用:根据配置的规则应用缩进、换行等格式化操作
- 美化代码输出:生成最终的格式化代码
关键API与扩展点
js-beautify提供了灵活的API,使得自定义扩展成为可能:
// 核心API结构
const js_beautify = require('js-beautify');
const css_beautify = require('css-beautify');
const html_beautify = require('html-beautify');
// 自定义HTML美化(可集成JS和CSS美化器)
function style_html(html_source, options, js, css) {
js = js || js_beautify;
css = css || css_beautify;
return html_beautify(html_source, options, js, css);
}
这一架构设计为我们处理ERB模板中的JavaScript代码提供了关键的扩展点。
解决方案:三步实现ERB模板JS美化
第一步:安装与基础配置
首先,确保你的开发环境中已安装Node.js和npm,然后通过npm安装js-beautify:
npm install js-beautify --save-dev
创建基础配置文件.jsbeautifyrc:
{
"indent_size": 2,
"indent_char": " ",
"indent_level": 0,
"indent_with_tabs": false,
"preserve_newlines": true,
"max_preserve_newlines": 2,
"jslint_happy": false,
"space_after_anon_function": true,
"brace_style": "collapse",
"keep_array_indentation": false,
"keep_function_indentation": false,
"space_before_conditional": true,
"break_chained_methods": false,
"eval_code": false,
"unescape_strings": false,
"wrap_line_length": 0,
"wrap_attributes": "auto",
"end_with_newline": true
}
第二步:构建ERB-JS专用格式化工具
创建一个Ruby脚本文件beautify_erb_js.rb,作为处理ERB模板的专用工具:
require 'tempfile'
class ErbJsBeautifier
def initialize(options = {})
@options = {
indent_size: 2,
indent_char: ' ',
preserve_newlines: true,
max_preserve_newlines: 2,
brace_style: 'collapse',
end_with_newline: true
}.merge(options)
end
# 处理ERB文件
def process_file(file_path)
content = File.read(file_path)
# 提取并替换ERB标签
processed_content = replace_erb_tags(content)
# 创建临时JS文件
temp_file = Tempfile.new(['erb_js', '.js'])
temp_file.write(processed_content)
temp_file.close
# 使用js-beautify格式化
beautified_content = run_js_beautify(temp_file.path)
# 恢复ERB标签
final_content = restore_erb_tags(beautified_content)
# 写回文件
File.write(file_path, final_content)
temp_file.unlink
end
private
# 替换ERB标签为特殊标记
def replace_erb_tags(content)
@erb_tags = []
content.gsub(/<%.*?%>/m) do |match|
tag_id = "ERB_TAG_#{@erb_tags.size}_#{rand(1000000)}"
@erb_tags << { id: tag_id, content: match }
tag_id
end
end
# 恢复ERB标签
def restore_erb_tags(content)
@erb_tags.each do |tag|
content.gsub!(tag[:id], tag[:content])
end
content
end
# 运行js-beautify命令
def run_js_beautify(file_path)
options = []
options << "--indent-size #{@options[:indent_size]}"
options << "--indent-char '#{@options[:indent_char]}'"
options << "--preserve-newlines #{@options[:preserve_newlines] ? 'on' : 'off'}"
options << "--max-preserve-newlines #{@options[:max_preserve_newlines]}"
options << "--brace-style #{@options[:brace_style]}"
options << "--end-with-newline #{@options[:end_with_newline] ? 'on' : 'off'}"
`js-beautify #{options.join(' ')} #{file_path}`
end
end
# 执行格式化
if ARGV.empty?
puts "Usage: ruby beautify_erb_js.rb <file1.erb> [file2.erb ...]"
exit 1
end
beautifier = ErbJsBeautifier.new
ARGV.each { |file| beautifier.process_file(file) }
第三步:高级配置与优化
为了处理更复杂的ERB-JS场景,我们需要进一步优化我们的解决方案:
- 添加ERB感知的缩进调整
# 在ErbJsBeautifier类中添加
def adjust_indentation_for_erb(content)
lines = content.split("\n")
indent_level = 0
result = []
lines.each do |line|
# 处理ERB条件标签
if line.include?('<% if') || line.include?('<% unless') || line.include?('<% while')
result << line
indent_level += @options[:indent_size] / 2
elsif line.include?('<% else') || line.include?('<% elsif')
indent_level -= @options[:indent_size] / 2
result << ' ' * indent_level + line.strip
indent_level += @options[:indent_size] / 2
elsif line.include?('<% end')
indent_level -= @options[:indent_size] / 2
result << ' ' * indent_level + line.strip
else
# 应用当前缩进级别
result << ' ' * indent_level + line.strip
end
end
result.join("\n")
end
- 集成到Rails开发流程
创建一个Rake任务lib/tasks/beautify.rake:
namespace :code do
desc "Beautify JavaScript in ERB templates"
task :beautify_erb_js do
require Rails.root.join('lib/beautify_erb_js')
beautifier = ErbJsBeautifier.new(
indent_size: 2,
preserve_newlines: true,
max_preserve_newlines: 2,
brace_style: 'collapse'
)
# 处理app/views下的所有ERB文件
Dir.glob(Rails.root.join('app/views/**/*.erb')).each do |file|
puts "Beautifying #{file}..."
beautifier.process_file(file)
end
end
end
- 添加Git提交前钩子
创建文件.git/hooks/pre-commit:
#!/bin/sh
# 检查修改的ERB文件并自动格式化
ERB_FILES=$(git diff --cached --name-only | grep '\.erb$')
if [ -n "$ERB_FILES" ]; then
echo "Beautifying JavaScript in ERB templates..."
ruby -r ./lib/beautify_erb_js -e "ErbJsBeautifier.new.process_file('$ERB_FILES')"
# 将格式化后的文件添加到提交
git add $ERB_FILES
fi
exit 0
实际应用案例:从混乱到优雅
案例1:复杂条件下的JS代码
格式化前:
<script>
<% if @user.admin? %>
$(document).ready(function(){
$('#admin-menu').show();
<% else %>
$(document).ready(function(){
$('#user-menu').show();
<% end %>
$('#notification').on('click', function(){
$(this).hide();
});
</script>
格式化后:
<script>
<% if @user.admin? %>
$(document).ready(function() {
$('#admin-menu').show();
});
<% else %>
$(document).ready(function() {
$('#user-menu').show();
});
<% end %>
$('#notification').on('click', function() {
$(this).hide();
});
</script>
案例2:包含ERB循环的JS数组
格式化前:
<script>
var userList = [
<% @users.each do |user| %>
{id: <%= user.id %>, name: '<%= user.name %>'},
<% end %>
];
function initUsers() {
<% if current_user %>
userList.forEach(function(user){
console.log(user.name);
});
<% end %>
}
</script>
格式化后:
<script>
var userList = [
<% @users.each do |user| %>
{ id: <%= user.id %>, name: '<%= user.name %>' },
<% end %>
];
function initUsers() {
<% if current_user %>
userList.forEach(function(user) {
console.log(user.name);
});
<% end %>
}
</script>
高级技巧与最佳实践
1. 自定义js-beautify规则
针对ERB模板的特殊性,建议使用以下自定义配置:
{
"indent_size": 2,
"preserve_newlines": true,
"max_preserve_newlines": 2,
"space_after_anon_function": true,
"brace_style": "collapse",
"space_in_paren": false,
"wrap_line_length": 100,
"end_with_newline": true,
"comma_first": false,
"operator_position": "before-newline"
}
2. ERB-JS代码风格指南
为团队制定清晰的ERB-JS代码风格指南:
- 标签放置:ERB标签应单独成行,避免与JS代码混在同一行
- 缩进规则:ERB条件块和JS代码块使用相同的缩进级别
- 空格使用:在ERB标签
<%=和%>前后各保留一个空格 - 换行策略:在
<% end %>后添加一个空行,分隔不同逻辑块 - 注释规范:使用JS注释
//而非ERB注释<%# %>注释JS逻辑
3. 性能优化
对于大型项目,可通过以下方式优化格式化性能:
# 添加增量处理功能
def process_changed_files_only
# 获取Git中修改的ERB文件
changed_files = `git diff --name-only --cached | grep '\.erb$'`.split("\n")
changed_files.each do |file|
process_file(file) if File.exist?(file)
end
end
常见问题与解决方案
问题1:ERB标签被错误格式化
症状:<%= user.name %>被格式化为<%=user.name%>
解决方案:修改替换策略,保留标签内的空格:
# 修改replace_erb_tags方法
def replace_erb_tags(content)
@erb_tags = []
content.gsub(/<%\s*=?\s*.*?\s*%>/m) do |match|
tag_id = "ERB_TAG_#{@erb_tags.size}_#{rand(1000000)}"
@erb_tags << { id: tag_id, content: match }
tag_id
end
end
问题2:JS字符串中的ERB标签被破坏
症状:"Hello <%= user.name %>"被错误拆分为多行
解决方案:增强字符串检测:
# 添加字符串检测逻辑
def contains_string_literal?(content, position)
# 简单的字符串检测逻辑
in_string = false
quote_char = ''
content[0...position].each_char do |c|
if !in_string && (c == '"' || c == "'")
in_string = true
quote_char = c
elsif in_string && c == quote_char && content[position-1] != '\\'
in_string = false
end
end
in_string
end
问题3:复杂嵌套条件的缩进混乱
症状:多层嵌套的<% if %>导致缩进层级错乱
解决方案:实现基于栈的缩进跟踪:
# 基于栈的缩进管理
def process_nested_conditions(content)
lines = content.split("\n")
indent_stack = []
result = []
lines.each do |line|
if line.include?('<% if') || line.include?('<% unless')
indent_stack << current_indent_level(line)
result << line
elsif line.include?('<% else')
indent_stack.pop
current_indent = indent_stack.last || 0
result << ' ' * current_indent + line.strip
indent_stack << current_indent
elsif line.include?('<% end')
indent_stack.pop
current_indent = indent_stack.last || 0
result << ' ' * current_indent + line.strip
else
result << line
end
end
result.join("\n")
end
总结与展望
通过本文介绍的方法,你已经掌握了在Ruby ERB模板中优雅处理JavaScript代码格式化的完整解决方案。从理解js-beautify的工作原理,到实现ERB标签的智能替换与恢复,再到优化缩进和集成到开发流程,我们一步步构建了一个强大而灵活的工具链。
随着Web开发技术的不断发展,未来我们可以期待:
- js-beautify原生支持ERB模板格式
- Ruby on Rails框架内置ERB-JS格式化功能
- IDE插件提供实时的ERB-JS格式化支持
无论如何,掌握本文介绍的技术,将立即提升你的开发效率和代码质量,让你的ERB模板中的JavaScript代码从混乱走向优雅。
附录:实用工具与资源
1. 完整的ERB-JS美化脚本
2. 配置模板
.jsbeautifyrc 完整配置
{
"indent_size": 2,
"indent_char": " ",
"indent_level": 0,
"indent_with_tabs": false,
"preserve_newlines": true,
"max_preserve_newlines": 2,
"jslint_happy": true,
"space_after_anon_function": true,
"brace_style": "collapse",
"keep_array_indentation": false,
"keep_function_indentation": false,
"space_before_conditional": true,
"break_chained_methods": false,
"eval_code": false,
"unescape_strings": false,
"wrap_line_length": 100,
"wrap_attributes": "auto",
"end_with_newline": true,
"comma_first": false,
"operator_position": "before-newline"
}
3. 自动化集成指南
VS Code配置:
{
"files.associations": {
"*.erb": "erb"
},
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[erb]": {
"editor.defaultFormatter": "you-sheng.vue-vscode-extensionpack"
}
}
通过这些工具和技术,你可以彻底解决ERB模板中JavaScript代码的格式化难题,显著提升开发效率和代码质量。现在就将这些方法应用到你的项目中,体验从混乱到优雅的转变吧!
【免费下载链接】js-beautify Beautifier for javascript 项目地址: https://gitcode.com/gh_mirrors/js/js-beautify
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



