Add once.js to core

Created on 5 January 2015, almost 10 years ago
Updated 28 December 2023, 11 months ago

Problem/Motivation

The once feature is used in almost all core behaviors. The once feature is implemented as a jQuery plugin, making it impossible to remove jQuery from core scripts.

Proposed resolution

Implement a version of the once feature that does not depend on jQuery

Remaining tasks

  1. benchmark

Dependency Evaluation

https://www.drupal.org/project/once is considered Drupal Core, there are no runtime dependencies. For dev dependencies see #3199444: Dependency evaluation

User interface changes

None

API changes

  1. Create a new core/once library
  2. Introduce the once global variable to eslint config
  3. A new library with 4 functions: once, once.filter (equivalent to jQuery.fn.findOnce), once.remove, once.find (new function not previously possible with the jQuery implementation)
  4. When once is called on elements it add a new data-once attribute to each element that holds all the once ids called

Release notes snippet

The once library has been added to replace the functionality provided by for jQuery .once function. The change record for the once library details how to use the new functionality.

Before

# mymodule.libraries.yml
myfeature:
  js: 
    js/myfeature.js: {}
  dependencies:
    - core/drupal
    - core/jquery
    - core/jquery.once
# js/myfeature.js
(function ($, Drupal) {
  Drupal.behaviors.myfeature = {
    attach(context) {
      const $elements = $(context).find('.myfeature').once('myfeature');
    }
  };
}(jQuery, Drupal));

After (removing jQuery dependency)

# mymodule.libraries.yml
myfeature:
  js: 
    js/myfeature.js: {}
  dependencies:
    - core/drupal
    - core/once
# js/myfeature.js
(function (Drupal, once) {
  Drupal.behaviors.myfeature = {
    attach(context) {
      const elements = once('myfeature', '.myfeature', context);
    }
  };
}(Drupal, once));

Release notes snippet

This adds the core/once library, a standalone library that offers the same benefits as core/jquery.once but without the jQuery dependency.

Original report by droplet

>Inspired from http://eleks.github.io/js2js/. Now I totally rewritten jQuery.once into Plain JavaScript Code. Aiming to provide a modern pattern widely used everywhere, not just the Drupal way.

Features / Changes:

  • Remove dependency on jQuery.
  • Use HTML5 data-* attribute (not the jQuery.data()). It's better for debugging and work with other scripts. eg. You now able to query it directly: document.querySelectorAll(["data-drupal-once"]))
  • Performance improvements
  • Fully pass jQuery.once testcases
  • Light weight & More easier to adopt other libs. eg. Converting to jQuery Chaining way: https://github.com/KayLeung/dropletOnce/blob/master/jquery.droplet.once.js

Performance testing result:
https://docs.google.com/spreadsheets/d/1KXVKZS-HJhbQFgUYUmzPzMpJpEMOPXyG...
** Noticeable performance diff on iPhones.

Testing Repo:
https://github.com/KayLeung/dropletOnce

The reason I do not like jQuery.Once 2.0:

  • jQuery adding overhead. Including libs size and execution time ( I'm doubt the performance improves between jQuery Once 1.0 .class way and Version 2.0 jQuery.data on modern browsers )
  • No standard identify for themer (.once-class)
  • No visual debugging info for themer ( You can't see the Onced elements in devtools. You must use JS to loop over to see if that elements if Onced or not. This is not friendly for HTML/CSS themers)
  • One way synced only. jQuery.Once 2.0 use jQuery.data to track Onced elements. It will not synced back to HTML DOM.
  • Not a modern way. Popular frameworks use standard HTML5 data-* attribute. Not the jQuery.data()
📌 Task
Status

Fixed

Version

9.2

Component
Javascript 

Last updated about 11 hours ago

Created by

🇭🇰Hong Kong droplet

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

Production build 0.71.5 2024