- Issue created by @larowlan
- πΊπΈUnited States andy-blum Ohio, USA
I love this idea, and think an addition to the libraries.yml would be the perfect place to declare es module usage. For example from the react module's current usage of the importmaps module:
react.libraries.yml
react: js: 'js/dist/react.js': { minified: true } react-dom: js: 'js/dist/react-dom.js': { minified: true } dependencies: - react/react
react.importmaps.yml
react: path: js/dist/react.js react-dom: path: js/dist/react-dom.js react/jsx-runtime: path: js/dist/react-jsx-runtime.js
To kick off some discussion here, re-imagining this as a single .libraries.yml file could become one of several options, each with their own benefits/drawbacks.
Option 1: Adding importpath info to a JS asset
react: js: 'js/dist/react.js': { minified: true, esmodule: 'react' } react-dom: js: 'js/dist/react-dom.js': { minified: true, esmodule: 'react-dom' } dependencies: - react/react
Pros:
- Minimal addition to the yaml structure
- Tight coupling to current libraries
Cons:
- JS files don't necessarily need to be loaded on a page for the import map to work, but this approach would add them into the DOM 100% of the time
Option 2: Adding importpath info to an individual library
react: js: 'js/dist/react.js': { minified: true } imports: 'react': 'js/dist/react.js' react-dom: js: 'js/dist/react-dom.js': { minified: true } imports: 'react-dom': 'js/dist/react-dom.js' dependencies: - react/react
Pros:
- Moderate coupling to current libraries
- Files that exist only as "sources" of modules won't get unnecessarily loaded to the page
Cons:
- Files that both need to both run *and* operate at a module's source have to be duplicated
Option 3: Adding importpath info as a separate non-library top level item
react: js: 'js/dist/react.js': { minified: true } react-dom: js: 'js/dist/react-dom.js': { minified: true } dependencies: - react/react IMPORT_PATH: 'react': 'js/dist/react.js' 'react-dom': 'js/dist/react-dom.js'
Pros:
- Offers the greatest flexibility
Cons:
- Loosest coupling to libraries
- Requires a "magic" library name
- π¦πΊAustralia larowlan π¦πΊπ.au GMT+10
Option 4
react-dom: importmaps: react: 'js/dist/react-dom.js'
ie another top level entry that isn't css/js
Because we really don't want the file attached as a regular js script. We want the browser to load it on demand.
Then another module that needs react-dom
my-amazing-library: js: 'js/dist/amazing-library.js': { minified: true, attributes: {type: 'module' }} dependencies: - react/react-dom
- π¦πΊAustralia larowlan π¦πΊπ.au GMT+10
Just realised there was no code in the importmaps contrib project, pushed that up
- πΊπΈUnited States andy-blum Ohio, USA
I think your option 4 is the same as my option 2, though?
- π¦πΊAustralia larowlan π¦πΊπ.au GMT+10
Ah, I saw you still had js: in option 2 so thought it was different. If you're saying the same think I think we should remove the js entry in it to make it clear that that the file needs to be loaded by the browser from the importmap instead of by a script tag/Drupals standard asset rendering
Do you have a preferred option? I think option 2 with the above caveat gets us closest to the intent here
- π¬π§United Kingdom longwave UK
Symfony's AssetMapper component provides support for importmaps, it doesn't look like we can fully leverage this component directly, but we could learn from it and perhaps use some of their code.
- π«π·France prudloff Lille
I started a POC contrib module that implements this: https://www.drupal.org/project/importmap β
It uses data attributes to avoid breaking the
libraries.yml
YAML schema. But if core implemented this, it could of course be with new properties in the YAML. - π¦πΊAustralia larowlan π¦πΊπ.au GMT+10
Hmm, thanks, but feels odd to create a competing module one week after I made one at drupal.org/project/importmaps - we should be collaborating (I mentioned it in comment 4)
- π©πͺGermany ChristianAdamski Berlin, Germany
nod_ β credited ChristianAdamski β .
- π«π·France nod_ Lille
in classic drupal fashion we're jumping the gun to implementation before getting the scope cleared up :)
I'm leaning towards option 2 with the "importmap" key to match what it's called in html.
That's why I'm very satisfied we have peast in core now, we can actually look into the js files and extract stuff. Ideally I'd like to dynamically build the dependencies from what's declared in the js file itself to avoid having to double-declare dependencies.
Closed β¨ Provide management/mechanism for JS/ES6 importmap Closed: duplicate since this one has more activity and a better issue summary.
- π«π·France prudloff Lille
Hmm, thanks, but feels odd to create a competing module one week after I made one at drupal.org/project/importmaps - we should be collaborating (I mentioned it in comment 4)
Sorry, I did not see your module. I was initially following the duplicate issue and not this one.
I created an issue about merging the two modules: β¨ Provide management/mechanism for JS/ES6 importmap Closed: duplicatein classic drupal fashion we're jumping the gun to implementation before getting the scope cleared up :)
We had a concrete need for this and thought it would be better to publish it as a contrib module, to get ideas rolling.
But I agree that we need to think about the best way to declare imports before adding this to core.My initial thought was that it would make sense to have this in the library definitions since these are in fact libraries. But I agree that we would almost never need to load a JS file both as an import and with a script tag, so I guess it can make sense to a have a separate YAML file for this.
- π«π·France prudloff Lille
That's why I'm very satisfied we have peast in core now, we can actually look into the js files and extract stuff. Ideally I'd like to dynamically build the dependencies from what's declared in the js file itself to avoid having to double-declare dependencies.
I don't think this would work with dynamic imports.
But I am not entirely sure we have to care about dependencies here.
Having a module in the import map has no effect if it is not imported by some other JS module. So we could always include every declared module in the import map and don't bother managing dependencies. - π¬π§United Kingdom catch
It is only tangentially related but there is also β¨ Support prefetch/preload/dns-prefetch in the libraries API Active where the main barrier is figuring out the definition format.
- π¬π§United Kingdom catch
Regardless of the format, anything marked for import needs to be completely excluded from Drupal's asset rendering (and aggregation if it's enabled). Drupal just should not be loading it at all; instead just providing the markup so it can be loaded on demand via the browser.
A top-level entry in libraries would not hurt here, because it then wouldn't be possible to mix imported vs. not scripts in a single library definition.
Can we be certain that we won't get a mix of libraries relying on importmaps vs. libraries relying on library dependencies? That seems like it would not be good.
- Assigned to larowlan
- Issue was unassigned.
- π¦πΊAustralia larowlan π¦πΊπ.au GMT+10
Made a start on this, pausing till next week.
Have added some fake stuff to core.libraries for testing sake and am seeing the console.log
This doesn't work with big pipe and we'll likely have similar issues with Ajax.
In my testing, there is no API to dynamically modify the importmap as new files are loaded.
Trying to remove the import map and add a new one (e.g. in an AjaxCommand) results in
Multiple import maps are not allowed.
Trying to rewrite the contents of the existing script tag results in the browser not detecting any new additions.
So I think we're probably going to need to build the importmap based on all known importmaps and output that.
Otherwise if bigpipe or an ajax response add new JS that requires the importmap we're out of luck
I'll work on that and test coverage next week
- π¦πΊAustralia larowlan π¦πΊπ.au GMT+10
Got confirmation that there is no API for dynamic imports - https://github.com/WICG/import-maps/issues/92
So will continue with loading them all upfront
- π«π·France nod_ Lille
If we hit some limits of the import map api, An alternative solution could be reaching into the js source and rewrite import paths at process/bundle time.
I'm worried that the import map will end up being massive for something like Drupal. Maybe not, we'll see when we get there I guess.
Do we need to worry about security if we have an import map with everything? I know we don't have access rules on js assets by design so it shouldn't be an issue but you never know.
- π«π·France prudloff Lille
Symfony has a FAQ page that points to this example: https://ux.symfony.com/
It is a production website with ~100 files in the import map.