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

Popper.js not working when --download is used #65

Closed
AleksandarJeftic opened this issue Nov 5, 2021 · 27 comments
Closed

Popper.js not working when --download is used #65

AleksandarJeftic opened this issue Nov 5, 2021 · 27 comments
Assignees

Comments

@AleksandarJeftic
Copy link

AleksandarJeftic commented Nov 5, 2021

I apologize in advance if this is not a importmap problem, I am still learning to use it.

I have problem with bootstrap configuration through importmaps, for some reason when I run bin/importmap pin bootstrap --download I am getting these errors in chrome console (jsdelivr, unpkg) cdn providers

GET http://localhost:3000/assets/modifiers/index.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-ce872054c46039b8d5939756969a7a008e8d1ab3907e72b141e9e4650641b9ea.js:1 GET http://localhost:3000/assets/enums.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-ce872054c46039b8d5939756969a7a008e8d1ab3907e72b141e9e4650641b9ea.js:6 GET http://localhost:3000/assets/popper.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-ce872054c46039b8d5939756969a7a008e8d1ab3907e72b141e9e4650641b9ea.js:8 GET http://localhost:3000/assets/popper-lite.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-ce872054c46039b8d5939756969a7a008e8d1ab3907e72b141e9e4650641b9ea.js:4 GET http://localhost:3000/assets/createPopper.js net::ERR_ABORTED 404 (Not Found)

when I use command without download option like this bin/importmap pin bootstrap it works properly...not sure what is the problem in both commands it uses same cdn link

errors below are from JSPM cdn provider

GET http://localhost:3000/_/40866a73.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/enums.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/modifiers/index.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/modifiers/eventListeners.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/modifiers/popperOffsets.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/modifiers/offset.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/modifiers/applyStyles.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/modifiers/flip.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/modifiers/preventOverflow.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/modifiers/arrow.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/modifiers/hide.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/popper-lite.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/utils/detectOverflow.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getBoundingClientRect.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getCompositeRect.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getNodeScroll.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getWindowScroll.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getWindow.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/instanceOf.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getHTMLElementScroll.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getNodeName.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getWindowScrollBarX.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getDocumentElement.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/isScrollParent.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getComputedStyle.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getLayoutRect.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/listScrollParents.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getParentNode.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getOffsetParent.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/_/08d18af5.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/_/03a0b0f1.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/_/5328de10.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/utils/getMainAxisFromPlacement.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/_/8937ec25.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/utils/getOppositePlacement.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/utils/computeAutoPlacement.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/utils/getOppositeVariationPlacement.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/_/ea19fa71.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/_/8d8f2f4c.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/_/c591086d.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/_/6e98d37c.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/modifiers/computeStyles.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getDocumentRect.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getViewportRect.js 404 (Not Found)

javascript/application.js

// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
import "@hotwired/turbo-rails"
import "controllers"

import "@popperjs/core"
import "bootstrap"

config/importmap.rb

# Pin npm packages by running ./bin/importmap

pin "application", preload: true
pin "@hotwired/turbo-rails", to: "turbo.js"
pin "@hotwired/stimulus", to: "stimulus.js"
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js"
pin_all_from "app/javascript/controllers", under: "controllers"
pin "bootstrap" # @5.1.3
pin "@popperjs/core", to: "@popperjs--core.js" # @2.10.2
@leehericks
Copy link
Contributor

Did you try manually pinning popperjs/core --download ?

@leehericks
Copy link
Contributor

Or does it show up in your importmap?

@AleksandarJeftic
Copy link
Author

AleksandarJeftic commented Nov 5, 2021

I unpinned and pinned only popper with bin/importmap pin @popperjs/core --download, getting same result as with bootstrap command.
It automatically adds popper in config/importmap.rb, if that's what you ask?

@dhh
Copy link
Member

dhh commented Nov 23, 2021

cc @guybedford

@guybedford
Copy link
Contributor

For packages that require multiple files present in a package structure, what is needed is to download all of the files of the package, and locate the mappings to the local folder.

So I think there are two problems:

  1. Determining which modules are part of a multi-module package (a package that doesn't optimize into a single file, because it has multiple public exported entry point modules with shared code between them). These cases can possibly be indicated during initial resolution with a flag.
  2. Informing the location of the download folder relative to the import map location so that the mappings can be set to the downloaded version for transitive dependency resolutions etc. This case only really applies when these packages have dependents themselves though, so can be treated as a follow-up issue I think.

For (1), the list of files of a package on JSPM can be iterated by reading the package.json "files" array which is always resolved to a flat array of files that can be fetched. So download logic could be updated to handle this case.

Alternatively it would be possible to restrict the workflows to single file modules only, or at least have a clear warning when non-single-file modules are loaded. But I think folder packages will ultimately need to be supported at some point.

@dhh
Copy link
Member

dhh commented Nov 23, 2021

Ah, yes, I had totally forgotten about this with multiple files. I remember we talked about it. I'll try to have a swing at amending the bin/importmap to deal with this case.

@dhh dhh self-assigned this Nov 23, 2021
@dhh
Copy link
Member

dhh commented Dec 8, 2021

@guybedford Trying to look into this now, and not quite sure how to detect the multi-file modules. I thought I could just compare the count of staticDeps to map/imports, but that doesn't seem like the case. Does this require an extension on the API side of JSPM?

@guybedford
Copy link
Contributor

@dhh would it work if we upgraded staticDeps and dynamicDeps to include the comprehensive dependency graph information? That way you could look up the RHS import map targets in this map to get the dependencies for any package?

I've posted an issue for an approach in jspm/generator#91, if that sounds like the right sort of thing I can update the API appropriately.

@guybedford
Copy link
Contributor

guybedford commented Dec 8, 2021

Actually thinking about this further, I think a more high-level checkout API would be needed for this sort of thing. I've posted a concept in jspm/generator#92.

Update: Instead a simple graph API is available for generation when using the graph option, outputting the dependency trace grouped by package boundaries, which should give all the info necessary to achieve any requirements here.

@chadrschroeder
Copy link

I think there is still an issue even when the --download flag isn't used. I have this code to attach a Bootstrap tooltip to an element:

import { Tooltip } from 'bootstrap'
new Tooltip(my_element)

This works when my app is using Webpacker.

If I switch to importmap-rails and run ./bin/importmap pin bootstrap I end up with something like:

# config/importmap.rb
pin "bootstrap", to: "https://ga.jspm.io/npm:[email protected]/dist/js/bootstrap.esm.js"
pin "@popperjs/core", to: "https://ga.jspm.io/npm:@popperjs/[email protected]/lib/index.js"

The page will load without any of the 404 errors noted in the issue description above. But when I hover over the tooltip element there's an error in the JavaScript console for:

Uncaught ReferenceError: process is not defined
createPopper.js:81 Uncaught ReferenceError: process is not defined

The code down in createPopper.js that is causing the problem is related to a process.env.NODE_ENV reference. This is a Node.js environment variable that Webpacker would make sure to set here:

// config/webpack/development.js
process.env.NODE_ENV = process.env.NODE_ENV || 'development'

@guybedford
Copy link
Contributor

@chadrschroeder process isn't defined in browsers in JavaScript - I would advise posting an issue directly to Popper.js to update the check to include a typeof process guard when doing this check.

@guybedford
Copy link
Contributor

Note as a quick fix you can also define it - <script>window.process = { env: {} }</script>

@chadrschroeder
Copy link

It looks like maybe this is really an issue with the URL provided by JSPM.org. When I use their Online Import Map Generator and I have "Browser" checked and "Node" unchecked, then I also see the https://ga.jspm.io/npm:@popperjs/[email protected]/lib/index.js URL that importmap-rails is using.

But the distribution targets documentation for Popper V2 says:

There are two different esm builds, one for bundler consumers (e.g. webpack, Rollup, etc..), which is located under /lib, and one for browsers with native support for ES Modules, under /dist/esm. The only difference within the two, is that the browser-compatible version doesn't make use of process.env.NODE_ENV to run development checks.

Here's a minimal example of an HTML document that uses some of the elements in the Popper.js tutorial.

<html>
  <head>
    <script type="importmap">{
      "imports": {
        "@popperjs/core": "https://ga.jspm.io/npm:@popperjs/[email protected]/lib/index.js"
      }
    }</script>
    <script type="module">
      import { createPopper } from "@popperjs/core";
      const button = document.querySelector("#button");
      const tooltip = document.querySelector("#tooltip");
      createPopper(button, tooltip);
    </script>
  </head>
  <body>
    <button id="button" aria-describedby="tooltip">My button</button>
    <div id="tooltip" role="tooltip">My tooltip</div>
  </body>
</html>

The full tooltip behavior isn't implemented in this example but it illustrates the problem. When the URL is:

https://ga.jspm.io/npm:@popperjs/[email protected]/lib/index.js

then the createPopper.js code includes process.env.NODE_ENV. When I manually change the URL to:

https://ga.jspm.io/npm:@popperjs/[email protected]/dist/esm/index.js

then the createPopper.js code doesn't include the process.env.NODE_ENV reference.

I'm going to post an issue to Popper.js to see if they can do something so that JSPM.org provides the correct URL.

@rromanchuk
Copy link

if (process.env.NODE_ENV !== "production") ....uggh that's an annoying branch to begin with, regardless of esm. Is that common for dist packages to do?

Can confirm modifying my importmap.rb to explicit /esm/index.js resource works. Sort of a bummer since this is a common hello world setup

@sedubois
Copy link

sedubois commented Jan 14, 2022

I also encounter 404 not found as described in the OP when using ./bin/importmap pin swiper --download. Three files are added to vendor/javascript/:

pin "swiper" # @7.4.1
pin "dom7" # @4.0.4
pin "ssr-window" # @4.0.2

And three files are downloaded to vendor/javascript/: swiper.js, dom7.js and ssr-window.js.

However swiper.js contains this code:

export{A as A11y,d as Autoplay,C as Controller,k as EffectCards,i as EffectCoverflow,j as EffectCreative,g as EffectCube,E as EffectFade,h as EffectFlip,f as FreeMode,G as Grid,c as HashNavigation,H as History,K as Keyboard,L as Lazy,e as Manipulation,M as Mousewheel,N as Navigation,P as Pagination,b as Parallax,a as Scrollbar,S as Swiper,T as Thumbs,V as Virtual,Z as Zoom,S as default}from"./_/6811b57d.js";import"ssr-window";import"dom7";

So it wants to import JS from a file ./_/6811b57d.js, but no such file got downloaded to vendor/javascript, so when rendering the page Error: 404 Not Found http://localhost:3000/assets/_/6811b57d.js is thrown in the JS console.

A workaround is to either avoid the --download option, or to add pin "_/6811b57d" to importmap.rb (beside the three other pins mentioned above) and manually download the file from CDN to vendor/javascript/_/6811b57d.js.

@loqimean
Copy link

loqimean commented Jan 29, 2022

I also encounter 404 not found as described in the OP when using ./bin/importmap pin swiper --download. Three files are added to vendor/javascript/:

pin "swiper" # @7.4.1
pin "dom7" # @4.0.4
pin "ssr-window" # @4.0.2

And three files are downloaded to vendor/javascript/: swiper.js, dom7.js and ssr-window.js.

However swiper.js contains this code:

export{A as A11y,d as Autoplay,C as Controller,k as EffectCards,i as EffectCoverflow,j as EffectCreative,g as EffectCube,E as EffectFade,h as EffectFlip,f as FreeMode,G as Grid,c as HashNavigation,H as History,K as Keyboard,L as Lazy,e as Manipulation,M as Mousewheel,N as Navigation,P as Pagination,b as Parallax,a as Scrollbar,S as Swiper,T as Thumbs,V as Virtual,Z as Zoom,S as default}from"./_/6811b57d.js";import"ssr-window";import"dom7";

So it wants to import JS from a file ./_/6811b57d.js, but no such file got downloaded to vendor/javascript, so when rendering the page Error: 404 Not Found http://localhost:3000/assets/_/6811b57d.js is thrown in the JS console.

A workaround is to either avoid the --download option, or to add pin "_/6811b57d" to importmap.rb (beside the three other pins mentioned above) and manually download the file from CDN to vendor/javascript/_/6811b57d.js.

Hey man, you can just copy code from https://unpkg.com/browse/[email protected]/swiper-bundle.js to your 'vendor/swiper.js' and it's will be good for you, 'cause I had some problem but resolve it just now). Importmap just does not load all library folder and instead load one file, which can not have all the needed code. Then in your file where you wanna use it just import all file import 'swiper';, that gives you all modules and just Swiper class

@darkamenosa
Copy link

My solution for this problem is: Going to bootstrap doc, download the file directly on CDN then, put it into vendor/ directory like this.

vendor/
     bootstrap.min.js
     popper.min.js

In the importmap.rb code just select the right name:

# Added libraries
pin "bootstrap", to: "bootstrap.min.js" 
pin "@popperjs/core", to: "popper.min.js"

Then import them normally, in application.js.

import "bootstrap"
import "@popperjs/core"

@dhh
Copy link
Member

dhh commented Jun 18, 2022

Would be nice perhaps with an FAQ about how to resolve particular packages that don't just work out of the box. If anyone wants to explore that, please open a PR for it.

@dhh dhh closed this as completed Jun 18, 2022
@rromanchuk
Copy link

@darkamenosa i basically did the same, just manually vendor the esm from the cdn. I just bumped bootstrap to 5.2 with bin/importmap pin bootstrap --download, and found myself again after searching. I should probably leave myself a comment, or even better, just submit doc PR.

These things are always easy to resolve, but can be confusing with all the unrelated noise. It's nice seeing utilities like https://www.jsdelivr.com/esm been using it for quick isolated inline sanity checks on the fly

nicolas-grekas added a commit to symfony/symfony that referenced this issue May 24, 2023
…ivr+esm (weaverryan, nicolas-grekas)

This PR was merged into the 6.3 branch.

Discussion
----------

[AssetMapper] Change default importmap "provider" to JsDelivr+esm

| Q             | A
| ------------- | ---
| Branch?       | 6.3
| Bug fix?      | yes
| New feature?  | yes
| Deprecations? | no
| Tickets       | None
| License       | MIT
| Doc PR        |Still TODO

We currently use the https://jspm.org/ API in `importmap:require` to find a CDN URL for an npm package - just like Rails. Unfortunately, this is NOT as robust as we had thought. For me, it's broken. 3 big issues:

A) **Not Combined**
Some packages are not packed/combined. Example: [chart.js/auto](https://ga.jspm.io/npm:[email protected]/auto/auto.js) imports other packages and results in 3 requests instead of 1. Not TERRIBLE... so here IS a terrible example: [`@popperjs`/core](https://ga.jspm.io/npm:`@popperjs`/[email protected]/lib/index.js) (needed by `bootstrap`) results in nearly 50 requests ❗

B) **Downloading Broken**
For some packages, downloading simply doesn't work - rails/importmap-rails#65. ``@popperjs`/core` is another good example. Many of its imports have the form `import"./utils/getOppositeVariationPlacement.js`. If we download the main file, it looks locally for that `utils/` file, which won't be there. [`@chart`.js/auto](https://ga.jspm.io/npm:[email protected]/auto/auto.js) is another example.

C) **process.env.NODE_ENV included**
Some packages (yes, again ``@popperjs`/core` is a great example!) contain `process.env.NODE_ENV` inside - rails/importmap-rails#65 (comment)

I believe that some package advertise an "esm" package... but just don't do a good job of creating it... or create it without the browser context in mind (or at least in a way that's inconvenient for downloading).

### jsDelivr to the rescue

THANKFULLY, jsDelivr seems to have a fantastic API/hosting that is *almost* exactly what we want: https://www.jsdelivr.com/?docs=esm

They deliver fully "packaged" modules, where the only import is for peer dependencies - e.g. https://cdn.jsdelivr.net/npm/[email protected]/+esm

There IS still an issue when downloading. "Peer imports" are relative -e.g. `import*as t from"/npm/`@popperjs`/[email protected]/+esm";` However, these imports follow a VERY strict pattern. So, when `--download` is passed, we parse these, download the peer dependency and update the import contents to ``@popperjs`/core`, which works with the importmap. It's not ideal that we need to do that, but it's straightforward and works great.

Sorry again for this late PR - I had assumed that jspm was robust because Rails is using it. It turns out it's robust... unless you hit a "bad" package, then it's terrible. And they're not that rare: on ux.symfony.com, I have hit several.

Thanks!

Commits
-------

b530dc3 [AssetMapper] Fix wiring resolvers, send requests in parallel and use readonly properties in MappedAsset
de44614 [AssetMapper] Change default importmap "provider" to JsDelivr+esm
@AnalyzePlatypus
Copy link

It's been a year and half now.

Just to be clear:
The official Rails Way for dealing with multi-file dependencies is to manually download them and copy them into the project?!
(Same solution was also proposed in #153)

So no dependency management, version control, or way to easily keep dependencies updated?

Also, according to the official Popper docs:

Managing dependencies by "directly downloading" them and placing them into your source code is not recommended for a variety of reasons, including missing out on feat/fix updates easily. Please use a versioning management system like a CDN or npm/Yarn.

There needs to be a better way.

@AnalyzePlatypus
Copy link

AnalyzePlatypus commented Nov 9, 2023

In the meantime, here's the exact workaround I used, for future readers.

This PR from the Symfony team found that JsDelivr's ESM mode was much better at packaging dependencies than JSPM. Symfony has accordingly migrated their ImportMap implementation to use JsDelivr instead.

However, when I tried running importmap pin with the --from jsdelivr option, it again downloaded an incomplete file without bundled dependencies.

The solution I landed on was:

  1. Run ./bin/importmap pin @popperjs/core --from jsdelivr --download. This downloads the partial Popper file into vendor/javascript/@popperjs--core.js
  2. Visit the JSDelivr page for @popper/core to get the link to the ESM build. (In my case it was https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/+esm)
  3. I opened the link in my browser and copied the contents.
  4. I pasted the JS code into vendor/javascript/@popperjs--core.js

Finally, I ran into the process.env issue, so had to apply @guybedford's fix to supply the process.env variable:

<!-- In app/views/layouts/application.html.erb -->
<script>
  window.process = { env: { NODE_ENV: 'production'} }
</script>

That did the trick for now.

If importmap-rails could generate the correct JsDelivr URL, it seems like this issue could be permanently solved.

@vietqhoang
Copy link
Contributor

vietqhoang commented Nov 14, 2023

The solution I landed on was:

1. Run `./bin/importmap pin @popperjs/core --from jsdelivr --download`. This downloads the partial Popper file into `vendor/javascript/@popperjs--core.js`

2. Visit the [JSDelivr page for @popper/core](https://www.jsdelivr.com/package/npm/@popperjs/core) to get the link to the ESM build. (In my case it was `https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/+esm`)

Just FYI, the process can be simplified by doing the following:

./bin/importmap pin @popperjs/[email protected]/+esm --download --from jsdelivr.

The command maps to the desired nested esm file. Running it returns the following message.

Pinning "@popperjs/core/+esm" to vendor/javascript/@popperjs/core/+esm.js via download from https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/+esm

And the following pin line will be added to importmap.rb:

pin "@popperjs/core/+esm", to: "@popperjs--core--+esm.js" # @2.11.8

The pin can now be referenced by @popperjs/core/+esm.

The reference can be manually updated if @popperjs/core/+esm is not desired or if you want audit and outdated commands to work. The outdated and audit command rely on the reference name to match exactly to the library's name in order to scan for updates.

For example, the pin reference can be updated back to the following:

pin "@popperjs/core", to: "@popperjs--core--+esm.js" # @2.11.8

I leave the to reference name alone since I prefer keeping the unique naming of the esm file to help identify the difference between it and something like normal @popperjs--core.

@AnalyzePlatypus
Copy link

Wow, thanks @vietqhoang!

This now works perfectly for me with latest:

1. Pin from JSDelivr

./bin/importmap pin @popperjs/core@latest/+esm --download --from jsdelivr

2. Add the fix for process.env

<!-- In app/views/layouts/application.html.erb -->
<script>
  window.process = { env: { NODE_ENV: 'production'} }
</script>

3. [Optional] Rename

Because I want audit and outdated to work, I manually changed the pin name:

# From this:
pin "@popperjs/core/+esm", to: "@popperjs--core--+esm.js" # @2.11.8

# To this:
pin "@popperjs/core", to: "@popperjs--core--+esm.js" # @2.11.8

That's all!

✅ One-line install (with some minor manual file tweaking)
✅ No manually copying of vendor files
✅ Correctly bundles all dependencies in a single file
audit and outdated commands work correctly
✅ Easily updatable (just run the command again)

It would be even better if we could specify the pin name as an argument to bin/importmap pin.
That way we could eliminate Step 3 entirely.

@lingceng
Copy link

lingceng commented Jan 1, 2024

Need change

pin "@popperjs/core", to: "@popperjs--core--+esm.js" 

to

pin "@popperjs/core", to: "@popperjs--core--esm.js"

And manually change the file name in vender.

Seems '+' is not legal in url path.

@jussihirvi
Copy link

jussihirvi commented Apr 3, 2024

FYI, the popper project has changed it's name to floating-ui, and at least for popper v2, they don't recommend "direct download".

"Managing dependencies by 'directly downloading' them and placing them into your source code is not recommended for a variety of reasons, including missing out on feat/fix updates easily. Please use a versioning management system like a CDN or npm/Yarn."

@rromanchuk
Copy link

Please use a versioning management system like a CDN or npm/Yarn."

no

@rromanchuk
Copy link

Also that doesn't make any sense, i'm literally using version control and a cdn. "CDN or NPM" is a wild statement to put in their README. We should be applying upstream pressure on maintainers of DOM manipulating libraries to distribute javascript for web browsers.

Updated 2024 version with importmap-rails >2

  • Pull the actual esm from jsdelivr
  • Rename file because of jsdelivr's obnoxious url route/convention
  • Come back to this thread in 2028
bin/importmap pin @popperjs/[email protected]/+esm  --from jsdelivr
mv vendor/javascript/@popperjs--core--+esm.js vendor/javascript/stupid-popper-lib-2024.js
# config/importmap.rb
pin "@popperjs/core", to: "stupid-popper-lib-2024.js"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests