How do I add jQuery to Mastodon 4.02 (using Rails 6 and Webpacker 4)?

427 views Asked by At

I'm following this question from 2020 How do I use jQuery in Rails 6.0.3.3? , but I'm not able to add jQuery to Rails 6 and Webpacker 4 in Mastodon 4.02 https://github.com/mastodon/mastodon However, I am able to add a custom.js file to load my jQuery function; it's the main jQuery library that isn't loading.


Edit 1/27/23

Takeaways:

Why don't I have an environment.js file? Is this because of Webpacker 4?

I tried the two other approaches below to load the jQuery library directly in app/views/layouts/application.html.haml, but both throw the generic Mastodon error page and their are no errors using journalctl -u mastodon-web. Neither of these work:

= javascript_pack_tag 'jquery-min' to load app/javascript/packs/jquery-min.js (where jquery-min.js is the jQuery library).

= javascript_include_tag "https://code.jquery.com/jquery-3.6.6.min.js"


Original question:

In Mastodon:~/live$ I run yarn add jquery and that returns:

yarn add v1.22.19
[1/6] Validating package.json...
[2/6] Resolving packages...
[3/6] Fetching packages...
[4/6] Linking dependencies...
warning Workspaces can only be enabled in private projects.
[5/6] Building fresh packages...
[6/6] Cleaning modules...
warning Workspaces can only be enabled in private projects.
success Saved 1 new dependency.
info Direct dependencies
└─ [email protected]
info All dependencies
└─ [email protected]
Done in 24.18s.

I see that jQuery has been added to package.json and yarn.lock.

I added require('jquery') to app/javascript/packs/application.js:

import './public-path';
import loadPolyfills from '../mastodon/load_polyfills';
import { start } from '../mastodon/common';

start();

loadPolyfills().then(async () => {
  const { default: main } = await import('mastodon/main');

  return main();
}).catch(e => {
  console.error(e);
});

require('jquery')
require('packs/custom') // custom.js file I added

But I don't have an environment.js file in the Mastodon site files, and the non-existent environment.js file should include this, as referenced in the linked question:

const { environment } = require("@rails/webpacker");
const webpack = require("webpack");

environment.plugins.append(
  "Provide",
  new webpack.ProvidePlugin({
    $: "jquery/src/jquery",
    jQuery: "jquery/src/jquery",
  })
);

module.exports = environment;

I run

RAILS_ENV=production bundle exec rake tmp:cache:clear
RAILS_ENV=production bundle exec rails assets:generate_static_pages

And then

RAILS_ENV=production bundle exec rails assets:precompile

and that outputs this:

yarn install v1.22.19
[1/6] Validating package.json...
[2/6] Resolving packages...
[3/6] Fetching packages...
[4/6] Linking dependencies...
warning Workspaces can only be enabled in private projects.
[5/6] Building fresh packages...
[6/6] Cleaning modules...
Done in 18.17s.
Everything's up-to-date. Nothing to do

I exit from the root account and run

systemctl restart mastodon-*

I test for jQuery in the console and it's not loading:

enter image description here

But, the packs/custom.js file is loading, as it contains

console.log("custom js is loaded");

and I see custom js is loaded in the console.

Any ideas? Why is jQuery not loading?

  1. Where is the environment.js file file?

  2. Is the notice warning Workspaces can only be enabled in private projects a serious error?

  3. I have run RAILS_ENV=production bundle exec rails assets:clobber to clear Webpacker and that doesn't help with the missing jQuery library.


Edit 1/25/23:

As per mechnicov's answer, this is the shared.js file in /config/webpack/, but no luck when adding

new webpack.ProvidePlugin({ $: "jquery", jQuery: "jquery" })

const webpack = require('webpack');
const { basename, dirname, join, relative, resolve } = require('path');
const { sync } = require('glob');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const AssetsManifestPlugin = require('webpack-assets-manifest');
const extname = require('path-complete-extname');
const { env, settings, themes, output } = require('./configuration');
const rules = require('./rules');
const localePackPaths = require('./generateLocalePacks');

const extensionGlob = `**/*{${settings.extensions.join(',')}}*`;
const entryPath = join(settings.source_path, settings.source_entry_path);
const packPaths = sync(join(entryPath, extensionGlob));

module.exports = {
  entry: Object.assign(
    packPaths.reduce((map, entry) => {
      const localMap = map;
      const namespace = relative(join(entryPath), dirname(entry));
      localMap[join(namespace, basename(entry, extname(entry)))] = resolve(entry);
      return localMap;
    }, {}),
    localePackPaths.reduce((map, entry) => {
      const localMap = map;
      localMap[basename(entry, extname(entry, extname(entry)))] = resolve(entry);
      return localMap;
    }, {}),
    Object.keys(themes).reduce((themePaths, name) => {
      themePaths[name] = resolve(join(settings.source_path, themes[name]));
      return themePaths;
    }, {}),
  ),

  output: {
    filename: 'js/[name]-[chunkhash].js',
    chunkFilename: 'js/[name]-[chunkhash].chunk.js',
    hotUpdateChunkFilename: 'js/[id]-[hash].hot-update.js',
    hashFunction: 'sha256',
    path: output.path,
    publicPath: output.publicPath,
  },

  optimization: {
    runtimeChunk: {
      name: 'common',
    },
    splitChunks: {
      cacheGroups: {
        default: false,
        vendors: false,
        common: {
          name: 'common',
          chunks: 'all',
          minChunks: 2,
          minSize: 0,
          test: /^(?!.*[\\\/]node_modules[\\\/]react-intl[\\\/]).+$/,
        },
      },
    },
    occurrenceOrder: true,
  },

  module: {
    rules: Object.keys(rules).map(key => rules[key]),
  },

  plugins: [

    new webpack.ProvidePlugin({ $: "jquery", jQuery: "jquery" }),

    new webpack.EnvironmentPlugin(JSON.parse(JSON.stringify(env))),
    new webpack.NormalModuleReplacementPlugin(
      /^history\//, (resource) => {
        // temporary fix for https://github.com/ReactTraining/react-router/issues/5576
        // to reduce bundle size
        resource.request = resource.request.replace(/^history/, 'history/es');
      },
    ),
    new MiniCssExtractPlugin({
      filename: 'css/[name]-[contenthash:8].css',
      chunkFilename: 'css/[name]-[contenthash:8].chunk.css',
    }),
    new AssetsManifestPlugin({
      integrity: true,
      integrityHashes: ['sha256'],
      entrypoints: true,
      writeToDisk: true,
      publicPath: true,
    }),
  ],

  resolve: {
    extensions: settings.extensions,
    modules: [
      resolve(settings.source_path),
      'node_modules',
    ],
  },

  resolveLoader: {
    modules: ['node_modules'],
  },

  node: {
    // Called by http-link-header in an API we never use, increases
    // bundle size unnecessarily
    Buffer: false,
  },
};
1

There are 1 answers

5
mechnicov On

Firstly add JQuery if don't have it in your package.json

yarn add jquery

As I see Mastodon have webpack

You can use it to install JQuery in the project

For this purpose you can add changes to config/webpack/shared.js or config/webpack/configuration.js

Probably first file is better. Because plugins are installed there and webpack importing is already present

But you can use second file too as you wish

Finally you need to add to plugins array such element

new webpack.ProvidePlugin({ $: "jquery", jQuery: "jquery" })