You need to enable JavaScript to run this app. Ruby on Rails 6中如何配置让app/assets下的JS经webpacker正确编译
优惠活动
大模型
产品
解决方案
定价
更多

Ruby on Rails 6中如何配置让app/assets下的JS经webpacker正确编译

问题根因说明

你遇到的报错本质是Rails 6.1 两套独立JS编译管线的边界错位问题:

  • webpacker 负责管辖app/javascript目录下的ES6+模块,全程做ES语法转译、依赖打包
  • 传统Sprockets资产管线负责处理app/assets目录下的静态资源,默认只会原样输出文件内容,不做ES模块语法解析、也不会自动关联yarn安装的node依赖

你把带import语法的JS放在了app/assets/javascripts路径下,又通过普通的javascript_include_tag直接引入了未经过任何转译的源文件;浏览器拿到带原生ES import的脚本时,因为没有给脚本加上type="module"属性,自然就会抛出Cannot use import statement outside a module的语法错误。
另外注意你描述的自定义文件存放路径有个笔误,app/asets/javascripts少了字符,实际Rails默认的静态JS目录是app/assets/javascripts,路径拼接错误也会间接导致资产加载异常。

下面提供两种可落地的解决方式,优先推荐更贴合项目默认架构的方案。


方案一:完全迁移到webpacker体系(官方推荐,零额外依赖)

这是Rails 6.1 之后默认的JS开发规范,完全不需要改动原有Sprockets的配置逻辑:

  • 把你原本写在app/assets/javascripts/test.js的代码,移动到webpacker管辖的目录下,比如新建app/javascript/custom/test.js,文件内容修改为:
    import jQuery from "jquery";
    
    function test() {
        console.log(jQuery.fn.jquery)
    }
    
    // 关键:模块作用域下定义的函数不会自动暴露到全局,需要手动挂到window才能被onclick调用
    window.test = test;
    
  • 在webpacker入口文件app/javascript/packs/application.js中引入jQuery和自定义JS:
    import jQuery from "jquery";
    // 把jQuery挂载到全局,避免后续业务代码调用缺依赖
    window.$ = jQuery;
    window.jQuery = jQuery;
    // 引入自定义的test.js
    import "../custom/test.js";
    
  • 视图层替换原有的引入方式,不需要单独引入test.js,直接加载打包好的入口文件即可:
    <%= javascript_pack_tag 'application' %>
    <button onclick="test()">Button</button>
    

这套流程下所有带ES import的文件都会被webpack自动转译、打包,从根源上避免原生语法不被浏览器识别的问题。


方案二:改造Sprockets配置支持ES语法解析(仅适用于存量项目)

如果因为历史代码兼容问题,必须保留app/assets/javascripts的目录结构,才需要对Sprockets做针对性改造:

  • 首先在Gemfile中添加ES转译依赖,执行bundle install安装:
    gem 'babel-transpiler'
    
  • 修改Sprockets初始化配置config/initializers/assets.rb,增加两个核心规则:
    # 允许Sprockets从node_modules目录查找yarn安装的依赖
    Rails.application.config.assets.paths << Rails.root.join('node_modules')
    # 给JS文件接入babel转译能力,支持ES6+语法
    Rails.application.config.assets.configure do |env|
      env.register_mime_type 'text/javascript', extensions: ['.js']
      env.register_transformer 'text/javascript', 'application/javascript', Babel::Transpiler
    end
    
  • 注意:Sprockets的依赖加载逻辑和webpack的ES模块解析逻辑不互通,你原来写的import jQuery from "jquery"无法被正确识别,需要替换成Sprockets支持的require引入方式:
    // app/assets/javascripts/test.js 内容
    //= require jquery/dist/jquery.min
    
    function test() {
        console.log(jQuery.fn.jquery)
    }
    
    // 同样需要将test方法暴露到全局,才能被按钮的onclick事件调用
    window.test = test;
    
  • 视图层的引入方式不需要修改,Sprockets在输出JS时会自动完成ES语法转译,不再抛出import相关的语法错误。

避坑提醒:很多人解决完import报错后还是会遇到按钮点击无响应的问题,核心原因就是在模块作用域内定义的函数不会自动绑定到全局window对象上,一定要手动把需要在视图层直接调用的方法挂到window上。

内容的提问来源于stack exchange,提问作者fermi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.30 21:45:04