Rails从Sprockets迁移至Webpacker后依赖包加载异常求助
Hey there! Let’s break down why you’re hitting these errors and get your dependencies working smoothly without manual includes.
Why This Is Happening
The core issue boils down to how Sprockets and Webpack handle JavaScript scope:
- Sprockets loads all scripts into the global
windowscope by default. Any library you include is available everywhere on the page, just like you’re used to. - Webpack (the engine behind Webpacker) uses module-level scope out of the box. When you
require()a library liked3orshortcut.js, it’s only accessible inside that specific module file—not on the globalwindowobject.
Your errors (like Uncaught ReferenceError: shortcut is not defined and the datamaps warning) pop up because scripts like datamaps.usa.min.js and your inline code are searching for these libraries on the global window, but Webpack hasn’t exposed them there.
Solution 1: Manually Attach Libraries to the Global Window
The fastest fix is to explicitly assign your required libraries to window in your pack file. Update app/javascript/packs/client_application.js to this:
// Attach libraries to window so they're globally accessible window.$ = window.jQuery = require("jquery"); window.shortcut = require("shortcut.js/shortcut"); window.d3 = require("d3/d3.min"); window.topojson = require("topojson"); // d3-tip can stay as-is if it attaches itself to the global d3 object require("js/d3_tip");
This makes $, jQuery, shortcut, d3, and topojson available globally—just like they were with Sprockets. You can then delete all the javascript_include_tag lines from your client.haml and only keep = javascript_pack_tag "client_application".
Solution 2: Use Webpack's ProvidePlugin (More Elegant)
For a cleaner, scalable approach, use Webpack’s ProvidePlugin. This tool automatically injects libraries into every module that references them, and also makes them available globally for older scripts that expect window-scoped variables.
- Open
config/webpack/environment.js. - Add this configuration:
const { environment } = require('@rails/webpacker'); const webpack = require('webpack'); // Inject global dependencies automatically environment.plugins.prepend('Provide', new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery', d3: 'd3/d3.min', topojson: 'topojson', shortcut: 'shortcut.js/shortcut' }) ); module.exports = environment;
- Restart your Webpack dev server (
bin/webpack-dev-server) to apply the changes.
With this setup, you can even remove the require() lines from your pack file if you don’t need them explicitly—Webpack will automatically include the libraries wherever they’re referenced (in your code or third-party scripts like datamaps).
Final Checks
- Restart your Rails server and Webpack dev server to ensure all changes take effect.
- Remove the manual
javascript_include_taglines fromclient.hamland test your app—your dependencies should now load correctly from the pack file alone.
内容的提问来源于stack exchange,提问作者Antarr Byrd

