webpack 5和shakapacker 7:jQuery未初始化

vxbzzdmp  于 2023-10-17  发布在  jQuery
关注(0)|答案(2)|浏览(101)

在将webpack 4.46.0升级到webpack 5.88.2和shakapacker 7.0.3(rails 6.1.7.6)后,出现了Uncaught ReferenceError: $ is not defined错误。这里是当前的设置:

package.json

{
  "name": "app",
  "private": true,
  "dependencies": {
    "@babel/runtime": "^7.22.15",
    "@fortawesome/fontawesome-free": "^6.4.2",
    "@hotwired/turbo-rails": "^7.3.0",
    "@popperjs/core": "^2.11.8",
    "@rails/ujs": "^7.0.8",
    "babel-loader": "^9.1.3",
    "bootstrap": "^5.3.1",
    "core-js": "^3.32.2",
    "corejs-typeahead": "^1.3.3",
    "css-loader": "^6.8.1",
    "exports-loader": "^4.0.0",
    "expose-loader": "^4.1.0",
    "file-loader": "^6.2.0",
    "flag-icons": "^6.11.0",
    "handlebars": "^4.7.8",
    "inflection": "^2.0.1",
    "jbuilder": "^0.0.5",
    "jquery": "^3.7.1",
    "jquery-ui": "^1.13.2",
    "jquery-ui-dist": "^1.13.2",
    "jquery-ujs": "^1.2.3",
    "jstree": "^3.3.15",
    "mini-css-extract-plugin": "^2.7.6",
    "moment": "^2.29.4",
    "popper.js": "^1.16.1",
    "postcss": "^8.4.29",
    "rails-erb-loader": "^5.5.2",
    "sass-loader": "^13.3.2",
    "shakapacker": "^7.0.3",
    "sidekiq": "^1.1.1",
    "style-loader": "^3.3.3",
    "webpack": "^5.88.2",
    "webpack-assets-manifest": "^5.1.0",
    "webpack-cli": "^5.1.4",
    "webpack-dev-server": "^4.15.1",
    "webpack-merge": "^5.9.0",
    "webpack-sources": "^3.2.3",
    "yarn": "^1.22.19"
  },
  "babel": {
    "presets": [
      "./node_modules/shakapacker/package/babel/preset.js"
    ]
  },
  "devDependencies": {
    "@babel/core": "^7.22.19",
    "@babel/plugin-proposal-class-properties": "^7.18.6",
    "@babel/plugin-proposal-object-rest-spread": "^7.20.7",
    "@babel/plugin-proposal-private-methods": "^7.18.6",
    "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
    "@babel/plugin-syntax-dynamic-import": "^7.8.3",
    "@babel/plugin-transform-destructuring": "^7.22.15",
    "@babel/plugin-transform-regenerator": "^7.22.10",
    "@babel/plugin-transform-runtime": "^7.22.15",
    "@babel/preset-env": "^7.22.15",
    "babel-plugin-macros": "^3.1.0",
    "clean-webpack-plugin": "^4.0.0",
    "compression-webpack-plugin": "^10.0.0",
    "moment-timezone": "^0.5.43",
    "regenerator-runtime": "^0.14.0",
    "sass": "^1.67.0",
    "stylus": "^0.60.0",
    "terser-webpack-plugin": "^5.3.9",
    "url-loader": "^4.1.1"
  }
}

config/webpack/webpack.config.js

const { generateWebpackConfig } = require('shakapacker')
const webpackConfig = generateWebpackConfig()
const customConfig = require('./custom')
module.exports = generateWebpackConfig()

config/webpack/custom.js

var path = require('path');
 var webpack = require('webpack');
 const MiniCssExtractPlugin = require("mini-css-extract-plugin");
 const devMode = (process.env.NODE_ENV !== "staging") && (process.env.NODE_ENV !== "production");

 module.exports = {
   mode: 'development',
   entry: '../../app/javascript/packs/application.js',
   output: {
     path: path.resolve(__dirname, '../public'),
     publicPath: 'public/',
     filename: '[name].js',   // could be omitted, that's the default
     assetModuleFilename: 'public/images/[name].[ext]'
   },
   resolve: {
     modules: ['node_modules'],
     extensions: ['.css', '.sass', '.scss', '.js', '.json'],
     alias: {
       jquery: 'jquery',
       'jquery-ui': 'jquery-ui/jquery-ui.js',
       typeahead: 'core-typeahead',
     }
   },
   module: {
     rules: [
       {
         test: /\.html\.erb$/,
         loader: 'rails-erb-loader'
       },
       {
         test: require.resolve('jquery'),
         loader: 'expose-loader',
         options: {
           exposes: ['$', 'jQuery'],
         },
       },
       {
         test: /\.s[ac]ss$/i,
         use: [
           devMode ? "style-loader" : MiniCssExtractPlugin.loader,
           "css-loader",
           "postcss-loader",
           "sass-loader",
           "style-loader",
         ],
       },
       {
         test: /\.(jpe?g|png|gif|svg|gif|png|jpg|eot|ttf|otf|woff|woff2)$/i,
         loader: 'file-loader'
       },
     ]
   },
   performance: {
     hints: false,
     maxEntrypointSize: 512000,
     maxAssetSize: 512000
   },
   optimization: {
     splitChunks: {
       chunks: 'all'
     }
   },
   progress: true,
   stats: {
     errorDetails: true, //this does show errors
     colors: true,
     modules: true,
     reasons: true
   }
 }

config/webpack/environment.js

const webpack = require('webpack');
const { generateWebpackConfig } = require('shakapacker')
const erb = require('./loaders/erb');

const customConfig = {
  resolve: {
    fallback: {
      dgram: false,
      fs: false,
      net: false,
      tls: false,
      child_process: false
    }
  }
};

environment.plugins.prepend('Provide', 
  new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    jquery: 'jquery',
    Popper: ['popper.js', 'default'],
    Rails: ['@rails/ujs'],
    moment: 'moment'
  })
);

environment.loaders.prepend('erb', erb);
environment.config.merge(customConfig);
module.exports = environment;

config/webpack/development.js

process.env.NODE_ENV = process.env.NODE_ENV || 'development'
const environment = require('./environment')
module.exports = environment.toWebpackConfig()

app/assets/JavaScript/packs/application.js

...
import $ from 'jquery';
window.jQuery = $;
window.$ = $;
import 'jquery-ui-dist/jquery-ui';
...

app/views/layouts/application.html.erb

...
<%= stylesheet_pack_tag 'application', :media => "all", :data => {:turbo => {:track => 'reload'}} %>
<%= javascript_pack_tag 'application', :data => {:turbo => {:track => 'reload'}, :defer => false} %>
...

没有出现编译错误,有没有什么线索可以解释为什么jquery没有加载?

trnvg8h3

trnvg8h31#

请查看Shakapacker README filev6 upgrade docs,其中提出了两种方法。我在这里引用它们:
1.使用expose-loader
如果你使用expose-loader全局公开jquery,在app/javascript/application.js中使用import $ from "expose-loader?exposes=$,jQuery!jquery",将defer: false选项传递给javascript_pack_tag
1.在webpack配置中使用resolve.alias

// config/webpack/custom.js
module.exports = {
  resolve: {
    alias: {
      jquery: 'jquery/src/jquery',
    }
  }
}

1.在webpack配置中使用ProvidePlugin

module.exports = {
  // ...
  plugins: [
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery'
    })
  ]
  // ...
};
neskvpey

neskvpey2#

我发现这个错误与webpacker/shakapacker配置无关,而是由于缺少'defer'属性而没有正确加载的js.erb文件。

app/views/layouts/application.html.erb

...
<%= stylesheet_pack_tag 'application', :media => "all", :data => {:turbo => {:track => 'reload'}} %>
<%= javascript_pack_tag 'application', :data => {:turbo => {:track => 'reload'}} %>
<%= javascript_include_tag '/js/browse_jstree.js' %>
...

Webpacker helper javascript_pack_tag将生成HTML代码,并将defer设置为默认值true(这是webpacker 5中的新功能)。

...
<script src="/packs/js/runtime-f910d2d79960fb33a2bb.js" data-turbo="{&quot;track&quot;:&quot;reload&quot;}" defer="defer"></script>
<script src="/packs/js/vendors-node_modules_hotwired_turbo_dist_turbo_es2017-esm_js-node_modules_rails_ujs_lib_asset-a849ed-49174ef89c67613e1ea1.js" data-turbo="{&quot;track&quot;:&quot;reload&quot;}" defer="defer"></script>
<script src="/packs/js/application-3f6a4df6f831f107218d.js" data-turbo="{&quot;track&quot;:&quot;reload&quot;}" defer="defer"></script>
<script src="/js/browse_jstree.js"></script>
...

因此,js.erb文件不会等待脚本,它将在jquery之前加载。将defer = true添加到javascript_include_tag修复了此问题

...
<%= javascript_include_tag '/js/browse_jstree.js', :defer => true %>
....

相关问题