Quantcast
Channel: Issues for Drupal core
Viewing all articles
Browse latest Browse all 313861

Add once.js to core

$
0
0

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. Write the code
  2. Benchmarks to validate the improvement:benchmark
  3. Fill in the change notice
  4. Create a change notice for the element.matches polyfill
  5. Have jsdoc for all functions
  6. Make the new once feature available as a standalone library that follows the requirements outlined in #3176918: [policy, no patch] Publishing / Maintaining JS libraries produced by Drupal that do not have a dependency on Drupal

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

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()

Viewing all articles
Browse latest Browse all 313861

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>