Rails 6中使用Webpack按子域名条件导入图片的实现咨询
问题根源
Webpack 是编译期静态分析依赖的工具,只要你写的 import/require 语句在编译阶段能被 Webpack 扫描到,不管运行时是否实际加载对应模块,相关资源都会被编译进产物。你之前的用法里,subdomainfoo.js 属于 Webpacker 默认扫描的 packs 目录下的入口文件,会被单独编译为独立 chunk,所以对应图片必然会被编译;如果发现访问非对应子域名时图片也被下载,大概率是相关导入逻辑被意外打进了公共的 application.js 包里。
可行实现方案
方案1:入口资源完全隔离(最推荐,适配同构建产物多子域名场景)
- 调整目录结构,将公共资源和子域名专属资源完全拆分:
app/javascript/images/ ├── common/ # 公共图片,所有子域名通用 └── subdomains/ ├── foo/ # foo子域名专属图片 └── bar/ # bar子域名专属图片 - 修改公共入口
app/javascript/packs/application.js中的导入逻辑,仅扫描公共图片目录:require.context('../images/common', true) - 为每个子域名创建独立的入口 pack,比如
app/javascript/packs/subdomain-foo.js:// 仅加载foo子域名的专属图片 require.context('../images/subdomains/foo', true) - 保留你现有的 ERB 条件加载逻辑即可:
这种方案下,每个子域名的专属资源会被单独打包到对应入口的 chunk 里,只有匹配子域名时才会被用户下载,不会出现多余加载的问题。<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> <%= javascript_pack_tag "subdomain-#{request.subdomain}", 'data-turbolinks-track': 'reload' if %w[foo bar].include?(request.subdomain) %>
方案2:公共目录托管子域名资源(无需额外配置,更轻量)
如果子域名图片不需要经过 Webpack 的压缩、指纹、转译等处理,可以直接将子域名专属图片放到 public/images/subdomains/ 对应子目录下,业务代码中直接根据当前域名拼接资源路径即可:
const subdomain = window.location.host.split('.')[0] const imgUrl = `/images/subdomains/${subdomain}/bar.png`
这种方案下 Webpack 不会处理这些资源,自然不会出现多余编译、加载的问题。如果需要做资源优化,可以单独配置 image-webpack-loader 把子域名图片批量处理后输出到对应 public 目录。
方案3:编译期隔离(仅适合单子域名单独构建场景)
如果你是每个子域名单独构建部署,可以直接在 Rails Webpacker 中接入自定义环境变量:
- 修改
config/webpack/environment.js配置,传入环境变量:const { NormalModuleReplacementPlugin } = require('webpack') const subdomain = process.env.RAILS_APP_SUBDOMAIN || 'common' environment.plugins.append( 'SubdomainResourceReplace', new NormalModuleReplacementPlugin(/^\.\/images\/subdomain-default/, (resource) => { resource.request = resource.request.replace('subdomain-default', `subdomain-${subdomain}`) }) ) module.exports = environment - 构建时传入对应子域名参数即可:
这种方案构建出的产物仅包含对应子域名的资源,完全没有多余内容,但缺点是每个子域名需要单独构建,不适合同构建产物适配多子域名的场景。RAILS_APP_SUBDOMAIN=foo rails assets:precompile
内容的提问来源于stack exchange,提问作者mathStudent001
相关产品推荐
相关产品推荐

