Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: ESM Import Maps #3990

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

colinmollenhour
Copy link
Member

@colinmollenhour colinmollenhour commented May 13, 2024

This PR adds a native method to make use of Import Maps in OpenMage. Import maps are very well supported by now (not IE11) and allow one to use modern Javascript (ES Modules) without any compilation or build tools like Webpack.

Note on browser support: All major browsers support the "import" statement and "importmap" type, but what is not widely supported are the very rarely used keywords "with" and "assert" as well as the "src=" attribute, but basic inline importmaps are well supported.

Discussion

I've opened a discussion topic to discuss the merits of the feature, alternatives, etc. Please use the PR primarily for code suggestions.

For example, see 65380d6 which adds a Vue app to the footer and renders some dynamic content from a JS file imported from the skin directory.
image
image

image

Previously this would require special "AMD", "UMD" or "Global" builds of projects that not all modules provide and some may pollute the global namespace and often require you to preload the assets even if they aren't used. Import maps allow you to define the import sources and then the browser will fetch them as-needed and all of the other reasons that imports are superior that have been developing for the last 10+ years.

  • The browser will load only what is needed so you can have a big import map but only load what the page uses
  • Multiple modules with the same dependencies can avoid duplicating each other if they use the same specifiers (e.g. 'vue')
  • Modules can also operate without conflicts using different versions if needed (e.g. 'vue@1' and 'vue@3' on the same page)
  • You can import directly from CDNs like import echarts from 'https://cdn.jsdelivr.net/npm/[email protected]/+esm' but this leaves urls with version specifiers scattered all over your code - with this there is one place to specify the import url
  • Support dev mode vs prod mode for better debugging without ugly hacks like temporary file changes
  • No huge JS bundles to download on page start - make use of npm while avoiding the Webpack/Gulp complexity
  • Take advantage of widely used CDNs for static assets to get better cache hit rate on first page load (no idea how well this works in practice)

By supporting import maps as a proper asset type in OpenMage, different modules can add the same imports without duplicating them (assuming the versions don't conflict). If there were conflicts that one really needed to support they could craft their own importmap.json file to support "scopes" as that is supported by the import map spec and respected by this PR.

How to generate dependencies

This update does not aim to be highly opinionated about how you maintain your import maps, just provide a way to include them in the head tag without conflicts.

In a complex project you might have many dependencies that have their own dependencies and you'd rather a tool like npm handle them than try to do it manually. Handling dependencies is left up to the end user but one way would be as follows:

  1. Create a npm module at js/my-bundle/package.json
  2. Add dependencies and npm install, creating package-lock.json
  3. Generate an importmap file using importly: npx importly < package-lock.json > importmap.json
  4. Add the importmap to your layout XML: <action method="addStaticImportMap"><name>my</name><file>my-bundle/importmap.json</file></action>

(An alternative to importly is JSPM:Generator.)

By using importmap.json files with the "scopes" keyword it would be possible for extensions to not conflict with one another at all. However, this PR is not opinionated in this regard. Establishing some conventions could help avoid future conflicts but I'm just trying to get the capability in the core first.

Overrides

Although the spec doesn't support multiple import maps, this OpenMage feature does by simply reading the JSON of each import map and merging it with the others and the single imports. In this way, one can override imports from other modules by clobbering its namespace.

API

Public layout methods added to page/html_head block:

addStaticImportMap($name, $path, $devPath = null, $referenceName = '*', $before = false)
addSkinImportMap($name, $path, $devPath = null, $referenceName = '*', $before = false)
addStaticImport($specifier, $fileOrUrl, $devFileOrUrl = null, $referenceName = '*', $before = false)
addSkinImport($specifier, $fileOrUrl, $devFileOrUrl = null, $referenceName = '*', $before = false)

TODO

@github-actions github-actions bot added Component: Core Relates to Mage_Core Component: Page Relates to Mage_Page labels May 13, 2024
Co-authored-by: Fabrizio Balliano <[email protected]>
@colinmollenhour
Copy link
Member Author

Oops, forgot to check for styling issues.. old habits, sorry.. Thanks for the suggestions, @fballiano

@colinmollenhour colinmollenhour marked this pull request as draft May 14, 2024 15:39
@colinmollenhour
Copy link
Member Author

Closing due to limited interest and unproven utility.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Component: Core Relates to Mage_Core Component: Page Relates to Mage_Page
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants