Problem/Motivation
Keeping libraries up to date is a manual process. Need to visit each library and check if there was a new release.
Proposed resolution
Introduce an automated way to check library status and update dependencies.
Workflow
The proposed workflow to update a library is:
yarn outdated
yarn upgrade X Y Z
yarn run rollup # command name subject to change.
Details
The goal is to provide a predictable experience on usage, minification, and debugging.
Overview
Rollup is used because it's easy to use and there is not much configuration necessary. It's also suited to package individual files/libraries whereas webpack is more turned towards handling a single project as a whole. Because Drupal is using it's own library/dependency handling it's easier to have individual files that are aggregated later.
To manage a library there are 4 steps:
yarn add -D <library>Add the package as a dev dependency with yarn, if a package doesn't exists in npm, use the git repository directly (needed for farbtastic)- Configure the rollup file by declaring 2 steps:
- Step 1: is to bring the unimified version of the library into the
assets/vendor/<library>/<library>.jsfile. This is done in rollup with a module import, rollup has a way of declaring 'virtual' module, that can declared inline. In short we can do the equivalent ofinclude "file";with
{ input: "entry", plugins: [ // avoid the need for a dedicated file somewhere on disk. virtual({ entry: 'import "<library>";' }), // Does the actual code 'include' resolve(), ], output: { file: 'assets/vendor/<library>/<library>.js }, }Now depending on the library format for umd files a simple
import "<library>"is needed, when the library is a proper JS module we need to be more explicit withimport Lib from "<library>"; export default Lib;so that the second step works (this is the case for sortable, js-cookies, once). - Step 2: is process (transform is needed + minifiy) the previous file and generate the corresponding map file. The transform is to serve the library in a format appropiate for ES5 browsers (umd or iife). If the file was already in a umd format, there is little to do (just need to change some terser configuration to prevent ending up with additional global variables). If the library was in a JS module format, it is transformed into a iife (not a umd because it's smaller and I haven't seen that format really used for anything on the browser side lately, trivial to change though.). An example of the code transformation happening for JS module to iife.
// 1. A JS module in a 'api.js' file const a = true; const api = () => a; export default api;// 2. contents of 'api.js' transformed into an iife var api = function () { const a = true; const api = () => a; return api; }();// 3. contents of the 'api.js' iife is minified with terser var api=function(){"use strict";return()=>true}(); //# sourceMappingURL=api.min.js.mapin the rollup file it's presented like this:
{ input: 'assets/vendor/<library>/<library>.js', // minify code plugins: [terser()], output: { file: 'assets/vendor/<library>/<library>.min.js', // Generate a sourcemap for debuggability. sourcemap: true, // Do not copy the unminifed source into the map file, we already have it in the <library>.js file. sourcemapExcludeSources: true, format: 'iife', // needed only for JS modules name: 'api', // needed only for JS modules }, }
- Step 1: is to bring the unimified version of the library into the
- Declare the library in core.libraries.yml
- Profit
Because changing dependencies file names can be disruptive there are some inconsistencies (underscore-min.js instead of underscore.min.js, farbtastic.js having the minified version of the library, etc.).
Minification/Debugging
The reason we don't use the minified version of the library is to make it possible to offer a consistent debugging experience.
Problem
In core map files are not always available and some behave 'strangely'. Because we manually copy/pasted library code in an arbitrary folder that doesn't follow the library package structure some strange things can happen. Let's take jquery-form as an example:
// Extract of the structure for the jquery-form package.
package.json
dist/jquery.form.min.js
dist/jquery.form.min.js.map
src/jquery.form.js
// Folder structure in drupal/core directory
assets/vendor/jquery-form/jquery.form.min.js
assets/vendor/jquery-form/jquery.form.min.js.map
With the map file pointing to ../src/jquery.form.js it gives us an experience where the jquery.form.js file appears to be under assets/vendor/src/jquery.form.js (it is even worst for the popper lib which appears directly under assets/src!). There are also libraries with map files that are not referenced, and not shown in the dev tools, which makes them useless.

Solution
When we generate the map file everything behaves as expected:

Remaining tasks
- Feedback
- Dependency evaluation
- File size comparison
User interface changes
None
Release notes snippet
| Comment | File | Size | Author |
|---|
Issue fork drupal-3185289
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
nod_Will post details later.
Comment #3
nod_Comment #4
andypostGreat change!
Comment #5
nod_the only thing we can't automate that easily are the jquery ui part and ckeditor. definitely possible to automate but not like this.
attaching the rollup config file by itself for easier review, that's where everything happens.
Comment #6
nod_Comment #7
nod_Comment #8
nod_Comment #9
nod_Comment #10
nod_Comment #11
xjmThe test fail from Dispatcher is:
Comment #12
nod_Seems like a problem that composer looks into the node_modules folder.
In any case, removed the ckeditor4 package, we can't do anything with, it was just so we get a warning that it's outdated. jquery ui and ckeditor will stay manually managed for now.
Comment #13
nod_didn't like the version bump on the js-cookie library. didn't pay too much attention to the lib version between the libraries.yml file and package.json, just want to get feedback on the tools, process, etc. we can sort out the "details" later.
Comment #14
lauriiiAwesome work! Thank you for working on this @nod_! This would make maintaining our dependency updates so much easier.
Few comments/questions:
Comment #15
nod_Comment #16
xjmAdding some tags and bumping priority; this issue is a big deal.
Comment #17
catchThis is not really my area at all, but it sounds like an excellent plan!
Leaving ckeditor and modernizr out for now seems fine - it'd be worth opening a follow-up to see if we can somehow integrate them later (maybe as part of ckeditor 5 migration or afterwards).
Comment #18
wim leers@lauriii just pointed me here.
WOAHHHHHHHHHHHHHHHHHHHHHHHH! 🤩🥳
Epic work, @nod_! 👏
+1
Comment #19
nod_Some rollup related version updates.
Had some leftover map files I forgot to delete.
Removed the source from map files to avoid duplicating code all over the place (hence the smaller patch).
No changes in generated minified files after the update.
Comment #20
lauriiiRe #15.4: I think the issue summary is at least a good start for the documentation. Let's start by moving it to somewhere where it's easier to find in future.
I've not used rollup personally before but I took a look at their documentation and it looks good 👍 Removing the needs FEFM review tag because I don't have concerns on the approach.
Comment #21
nod_Comment #22
GrandmaGlassesRopeMan@_nod 👋
This is really nice. I wonder if it makes sense to keep the configuration for Rollup in a meta format? It seems like there is a lot going on `rollup.config.js` with lots of the entries being mostly repeated. Perhaps it could be automatically generated at runtime?
Comment #23
GrandmaGlassesRopeManI also considered if this could be generated automatically by looking through the filesystem, but I'm not sure if the virtual imports could be figured out easily.
Comment #24
nod_That was the first thing I did actually. But then you run into issues like backbone or farbtastic file naming is not consistent with the rest of the libraries. Then when the library is umd you need to remove some optimisations in terser, for some libraries you need to reference a specific file, not the default
import "<library>";because the file is already minified in a format we don't want to be using.At that point there is so much "non default" cases you end up remaking the rollup config and add a mapping layer in between. So I gave that up and went all-in with rollup. It's an internal dependency so we won't have to support a BC layer if we ever go to webpack or something else.
Comment #25
justafishComment #27
lauriiiRerolled patch from #15 and created separate patch without the dist file changes to make it easier to review.
Comment #28
nod_hiding files, use the merge request to review/update code.
Comment #29
nod_Started change record: https://www.drupal.org/node/3197544
Comment #30
xjmThere are some CSpell-related fails in the latest commits. The file should probably be added to the skipped files.
Comment #31
droplet commentedAt this point, those new tools for a few committers only. As a developer, I don't want these vendor Dependencies in package.json. It's very bloated.
I suggested creating a new package `drupal-vendor-tools` for these new updates. (It's for CORE committers only, no BC. Break it anytime)
If the upstream packages provided min files, to re-compress it again is a bad idea IMO. Or you should re-run the tests again.
Comment #32
nod_I'm not sure about the recompressing either. It should be safe enough but you're correct we should be testing it somehow if we do that. One issue I have with vendor provided minified files it's the map files paths like I showed in the issue summary, unless we add more folders inside the vendors directories it'll keep being messy. If we do that we might break libraries overrides because file path changed. Happy to hear suggestions :)
I think we will end up having a 'core-js' package that includes most of the stuff we need but I don't want to hold up this patch on this. This will make lib updates easier right away. People are not supposed to be using the core/package.json how would that be an issue to have more dependencies in it?
Comment #34
pasqualleAs I know webpack is needed to build CKEditor 5 plugins. I have a feeling we are trying to use 2 different JS module bundlers with Drupal.
related:
Drupal CKEditor plugin: https://git.drupalcode.org/project/ckeditor5/-/blob/1.0.x/README.md#drup...
No rollup for CKEditor: https://github.com/ckeditor/ckeditor5/issues/2140
Webpack5 for CKEditor: https://github.com/ckeditor/ckeditor5/issues/9799
Comment #35
nod_It's on my radar, I want to swap rollup with something else (most likely webpack) because webpack is used in symfony, most popular from the decoupled survey too. Personally I'd like something like esbuild but core is not really the place for tooling experiments.
The current patch has issues, like droplet said in #31 if we minify we should run the test suites all over again for each dependency. So better to avoid it. Most likely whatever we use will end up as a glorified copy/paste tool to extract dist files from packages and placing them where we need it.
I started to look at map files and see if we can force some path changes to fix part of the issue outlined in the US regarding debugging, if that's possible that would solve my main issue with pre-minified files.Ok that was way easier than expected, if we change the file path in the map file, it'll "just work", so yay.having a dedicated package for core contributors/committers outside of drupal root is also a good idea. When we get back the drupal_js namespace we'll look into that.
Comment #36
nod_actually don't need webpack/rollup, simple copy paste works just as well: #3219088: Use package.json to manage third party JS libraries