importmap-rails icon indicating copy to clipboard operation
importmap-rails copied to clipboard

[Feature] Outdated packages considers package dependencies

Open coder2000 opened this issue 3 years ago • 7 comments
trafficstars

I don't know how easy it would be to add given how the pins are kept but it would be nice if the outdated packages considered the dependencies of other packages. Currently I use Dropzone,js in my app, and it depends on just-extend. There is a new version of just-extend but Dropzone would break as it's requirements are different. Taking that into consideration would be easier than wondering why scripts are breaking.

coder2000 avatar Jun 11 '22 22:06 coder2000

I have a similar problem where jquery from cdn.jsdelivr.net works for me and jquery from ga.jspm.io doesn't work. For this reason I have the pin set to jsdelivr like this:

pin "jquery", to: "https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.js"

However, when I use the importmap command to pin blueimp-file-upload, it changes the jquery pin to use jspm, as seen here:

% bin/importmap pin blueimp-file-upload
Pinning "blueimp-file-upload" to https://ga.jspm.io/npm:[email protected]/js/jquery.fileupload.js
Pinning "jquery" to https://ga.jspm.io/npm:[email protected]/dist/jquery.js

You may have noticed that it upgraded from 3.6.0 to 3.6.3. I verified that the problem is not the version number by trying jquery 3.6.3 from jsdelivr. It worked fine. After changing that, I ran the command for pinning blueimp-file-upload and it changes jquery to using jspm again. In other words, it just replaces that line no matter what. In fact, the line that it will replace is entirely chosen by the name of the module, in this case just "jquery", which is a little bit of a problem because you can (usefully) pin things to whatever module name you want, and if you don't know it is a name for an npm package, or worse, it becomes an npm package after you start using that name, it will change that line that has nothing to do with the npm package, and you'll have a confusing problem to deal with.

This command is supposed to be for convenience, so I can understand if it isn't able to take conflicting dependencies into account. However, the fact that the documentation uses it, and the fact that it is even available, means that it should, at the very least, not replace lines quite so blindly and unexpectedly, especially in a file that is also meant to be edited manually. Especially when you consider that I might not commit the file after every change I make to it.

My proposal would be that when it is pinning dependencies and it encounters one that is already in the file, until the point where it does something a little smarter, it should just make no changes to that line.

As far as doing something smarter, I'm not sure I know enough to know what it should be, but it might be:

  • update the line only if the version number is the only thing that will get updated (don't change the host, don't update the line if it isn't using a cdn), and probably print something saying that this happened
  • somehow indicate which lines were added by the importmap command and, if necessary, options given such as cdn source, so that you can update only the automatically generated pins and only in such a way that dependency updates won't undo whatever options were selected when you pinned the package the first time

As it stands, I would at least be able to work around the problem if there was a way to indicate which pins should not be touched. Instead, I think my best option is that every time I change a package in a manual way I will copy that line and comment it, and basically say, "If these lines don't match, you've probably run the importmap command and it has probably updated this package to something you don't want." And then I'll have to either avoid the command (which would be inconvenient and I would likely forget at some point) or check the file for these notes every time I run it. And/Or maybe wrap bin/importmap in something that reminds me to check the notes.

toddcesere avatar Jan 25 '23 03:01 toddcesere

JSPM Generator has two features that may be able to help here:

  1. The inputMap option allows providing an import map as input, where versions and resolutions from that input map are respected as a source of truth for resolution.
  2. The provider option allows choosing a provider to use for all resolutions. In general this option tries to switch all resolutions over to the provided provider rather than acting as multi-provider as the idea here is that there is benefit in unifying on one CDN (single source of failure) over multiple from a reliability perspective. (It's only within a single CDN domain, that multi-CDN architecture makes sense for redundancy of course).

guybedford avatar Jan 26 '23 16:01 guybedford

Using the inputMap could help address some of the concerns about implementing scopes (https://github.com/rails/importmap-rails/issues/148).

I did some experimenting with the Generate API, and I've noticed there is no way to uninstall packages when passing in the inputMap. @guybedford Is there a plan for uninstalling with the inputMap; and if there is, how would it handle uninstalling dependencies?

To me, it seems like if we did a little bit of work just keeping track of what is a dependency and what has been installed by the user, we could work without using the inputMap and just pass a more complete list of packages into the install argument when pinning and unpinning.

Using the inputMap param

Pinning:

POST https://api.jspm.io/generate, body:

{
    "install": [ "alpinejs" ],
    "flattenScope": true,
    "env": [ "browser", "module" ],
    "inputMap": {
        "imports": {
            "react": "https://ga.jspm.io/npm:[email protected]/index.js"
        }
    }
}

Returning:

{
    "staticDeps": [
        "https://ga.jspm.io/npm:[email protected]/dist/module.esm.js",
        "https://ga.jspm.io/npm:[email protected]/index.js"
    ],
    "dynamicDeps": [],
    "map": {
        "imports": {
            "alpinejs": "https://ga.jspm.io/npm:[email protected]/dist/module.esm.js",
            "react": "https://ga.jspm.io/npm:[email protected]/index.js"
        }
    }
}

This installs the package alongside the existing ones

Updating:

POST https://api.jspm.io/generate, body:

{
    "install": [ "alpinejs" ],
    "flattenScope": true,
    "env": [ "browser", "module" ],
    "inputMap": {
        "imports": {
            "alpinejs": "https://ga.jspm.io/npm:[email protected]/dist/module.esm.js"
        }
    }
}

Response:

{
    "staticDeps": [
        "https://ga.jspm.io/npm:[email protected]/dist/module.esm.js"
    ],
    "dynamicDeps": [],
    "map": {
        "imports": {
            "alpinejs": "https://ga.jspm.io/npm:[email protected]/dist/module.esm.js"
        }
    }
}

This updates the package to the latest version.

Unpinning...

There is no "uninstall" or "remove" parameter here?

Without passing inputMap but we keep track of installed packages

Pinning

POST https://api.jspm.io/generate, body:

{
    "install": [ "alpinejs", "[email protected]" ],
    "flattenScope": true,
    "env": [ "browser", "module" ]
}

response:

{
    "staticDeps": [
        "https://ga.jspm.io/npm:[email protected]/dist/module.esm.js",
        "https://ga.jspm.io/npm:[email protected]/index.js"
    ],
    "dynamicDeps": [],
    "map": {
        "imports": {
            "alpinejs": "https://ga.jspm.io/npm:[email protected]/dist/module.esm.js",
            "react": "https://ga.jspm.io/npm:[email protected]/index.js"
        }
    }
}

Installs alpinejs latest and keeps react at its current version

Updating

Same as above - for packages we want to update, we just don't include their version in the install part

Unpinning

Similar to above - for packages we want to unpin, we just omit them from install.

Caleb-T-Owens avatar Jan 28 '24 14:01 Caleb-T-Owens

@Caleb-T-Owens you're 100% right about these package management features in inputMap. Currently the generate API doesn't support the uninstall and update functions of the generator (https://github.com/jspm/generator/blob/main/src/generator.ts#L1107, https://github.com/jspm/generator/blob/main/src/generator.ts#L1039), but we could add these to the API by supporting update or uninstall in place of the install key currently, to provide iterative package management workflows.

I'm all out of time for this weekend now, but will add it to my list for next weekend if that might be useful.

guybedford avatar Jan 29 '24 05:01 guybedford

Just following up here to check if there would be interest in the /update and /uninstall API features against inputMap?

guybedford avatar Feb 12 '24 04:02 guybedford

I am assuming that using the update API feature would add the ability to update dependent packages at the same time rather than potentially breaking dependencies? Then yes.

coder2000 avatar Feb 12 '24 05:02 coder2000

@coder2000 yes it will automatically update subdependencies as well, even if they are top-level imports too. I added this update feature in https://jspm.org/cdn/api#generate-operation.

guybedford avatar Feb 20 '24 06:02 guybedford