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

chore(core): update build #977

Merged
merged 36 commits into from
Oct 26, 2023
Merged

chore(core): update build #977

merged 36 commits into from
Oct 26, 2023

Conversation

etowahadams
Copy link
Contributor

@etowahadams etowahadams commented Sep 28, 2023

Fix #
Toward #

Change List

  • Removes /embed entrypoint
  • Removes umd build
  • Adds "exports" field to package.json
  • Adds knip
  • Removes unused dependencies
  • Removes unused files
  • Removes some unused methods
  • Make all CI/CD run on Node 20
  • Updates gosling.js HTML template to use module imports
  • Upgrade vite and vitest
  • replace @vitejs/plugin-react-refresh with @vitejs/plugin-react

Checklist

  • Ensure the PR works with all demos on the online editor
  • Unit tests added or updated
  • Examples added or updated
  • Documentation updated (e.g., added API functions)
  • Screenshots for visual changes (e.g., new encoding support or UI change on Editor)

@etowahadams etowahadams changed the title chore: update build chore(core): update build Sep 28, 2023
@etowahadams
Copy link
Contributor Author

The main thing remaining is to change getHtmlTemplate so that it uses esm.sh or something similar instead of the current unpkg. Will do that tomorrow.

Also also I'm wondering if should get rid of knip since it only supports Node 16+. Or try downgrading it assuming it used to support Node 14. I cut most of the dependencies knip marked as unused. There's also a bunch of exports (export const ...) that don't get used outside of the file they're defined in. I might deleting the export from those later.

@etowahadams
Copy link
Contributor Author

I've been experimenting with using esm.sh. Because HiGlass is UMD and not ESM, esm.sh can't get find any of the exports from HiGlass that Gosling uses.

Uncaught SyntaxError: The requested module '/v132/[email protected]/X-ZC9waXhpLmpzQDYuNS4xMCxyZWFjdC1kb21AMTcuMC4yLHJlYWN0QDE3LjAuMg/es2022/higlass.mjs' does not provide an export named 'HiGlassComponent' (at gosling.mjs:3:2125)

@manzt Do you think it would be worth updating HiGlass to give it a ESM build? I see that what happens now is that it creates a higlass.umd.js which gets transpiled using babel (with plugin transform classes).

The only alternative I can think of is to use importmaps. Its less clean but would probably get the job done.

Here's the HTML I've been playing with:

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="https://esm.sh/[email protected]/dist/hglib.css">
  </head>
  <body>
    <div id="gosling-container"></div>
  </body>
  <script type="module">
    // you can import submodules from esm.sh
    import { embed } from "https://esm.sh/[email protected]?deps=react@17,react-dom@17,pixi.js@6,[email protected]";
    embed(document.getElementById('gosling-container'), {
  "title": "Basic Marks: bar",
  "subtitle": "Tutorial Examples",
  "tracks": [
    {
      "layout": "linear",
      "width": 800,
      "height": 180,
      "data": {
        "url": "https://resgen.io/api/v1/tileset_info/?d=UvVPeLHuRDiYA3qwFlm7xQ",
        "type": "multivec",
        "row": "sample",
        "column": "position",
        "value": "peak",
        "categories": ["sample 1"],
        "binSize": 5
      },
      "mark": "bar",
      "x": {"field": "start", "type": "genomic", "axis": "bottom"},
      "xe": {"field": "end", "type": "genomic"},
      "y": {"field": "peak", "type": "quantitative", "axis": "right"},
      "size": {"value": 5}
    }
  ]
})
    </script>
</html>

@manzt
Copy link
Member

manzt commented Sep 29, 2023

Excited to see progress on this! Will try to take closer look this weekend. But just wanted to chime in.

Also also I'm wondering if should get rid of knip since it only supports Node 16+.

If gosling really just runs in the browser, I don't really see a motivation to support legacy versions of Node.js for development purposes. Node 14 and 16 are both EOL, meaning they are no longer being developed or will receive security fixes https://endoflife.date/nodejs). I'd look into using Node 20 and maybe consider just testing in that environment. Could reduce CI times.

@manzt Do you think it would be worth updating HiGlass to give it a ESM build? I see that what happens now is that it creates a higlass.umd.js which gets transpiled using babel (with plugin transform classes).

Yeah, I think that would be nice downstream. HiGlass will need to keep UMD for some time, due to its plugin system and other projects that rely on using it through script tags (many more higlass developers).

However, one thing I've been very interested in there is breaking up higlass into smaller packages that are pure ESM. We would then have @higlass/* which something like gosling could depend on, and then just have a top level higlass that imports these things and publishes to npm.

@etowahadams
Copy link
Contributor Author

I'd look into using Node 20 and maybe consider just testing in that environment. Could reduce CI times.

Good idea, I'll try it out!

However, one thing I've been very interested in there is breaking up higlass into smaller packages that are pure ESM

Agreed and I would expect this to be relevant to our previous discussion too.

@etowahadams
Copy link
Contributor Author

etowahadams commented Oct 4, 2023

edit: using the?bundle option with esm.sh works!

esm.sh

I attempted with importmaps and the esm.sh CDN but without success.

It seems that esm.sh doesn't have the pixi v6.x so it keeps using pixi v5.3.12. I noticed this because the error relates to not being able to import this es6-promise-polyfill package. Not sure why it can't import this package.

/* esm.sh - esbuild bundle(@pixi/[email protected]) es2022 production */
import {Polyfill as f} from "/v132/[email protected]/es2022/es6-promise-polyfill.mjs";

Here is the html:

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/hglib.css">

    <script type="importmap">
    {
    "imports": {
        "react": "https://esm.sh/react@17",
        "react-dom": "https://esm.sh/react-dom@17",
        "pixi.js": "https://esm.sh/pixi.js@6",
        "higlass": "https://esm.sh/[email protected]",
        "gosling.js": "https://esm.sh/[email protected]"
    }
    }
    </script>
<body>
    <div id="gosling-container"></div>
  
    <script type="module">
      import { embed } from 'gosling.js';
    embed(document.getElementById('gosling-container'), {
  .... same spec as above }
    </script>
</body>
</html>

skypack.dev

I also tried using another CDN called skypack.dev, without success, although with a different error.

Uncaught SyntaxError: The requested module 'gosling.js' does not provide an export named 'embed'

This error is a bit surprising because dist/gosling.es.js does have an export called embed

export { GoslingComponent, GoslingSchema, GoslingTemplates, theme_schema as ThemeSchema, compile, embed, init, name, validateGoslingSpec, version };

Next steps

I'm wondering what the best way to go about troubleshooting this. Perhaps there is something obvious I'm missing, or perhaps there's some deeper understanding of how these CDNs work that I'm missing. My hunch is that there's something wrong with the higlass or gosling build that is causing these difficulties? More to investigate.

Comment on lines 16 to 20
"react": "https://esm.sh/react@${reactVersion}?bundle",
"react-dom": "https://esm.sh/react-dom@${reactVersion}?bundle",
"pixi.js": "https://esm.sh/pixi.js@${pixiVersion}?bundle",
"higlass": "https://esm.sh/higlass@${higlassVersion}?bundle",
"gosling.js": "https://esm.sh/gosling.js@${goslingVersion}?bundle"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With ?bundle I'm actually not sure gosling.js has any imports to resolve. I would be curious about just using:

        import { embed } from 'https://esm.sh/gosling.js?bundle';

below. The main issue I issue I see with this is that I'm not sure how to control the version of HiGlass so that it aligns with the css.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

esm.sh says

In bundle mode, all dependencies are bundled into a single JS file except the peer dependencies.

So actually I don't need to import Higlass! Just react, react-dom, and pixi.js

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually you're right that does work! I'm surprised though. I'll have to read more about this bundle option.

import { embed } from "https://esm.sh/[email protected]?bundle"
embed(document.getElementById('gosling-container'), {...}

@etowahadams
Copy link
Contributor Author

Node 20 has the Web Crypto API built in (globalThis.crypto). But Node 18 doesn't.

Because of this, using changing crypto with vi.stubGlobal or globalThis or window works in Node 18 but not Node 20 (else you get a TypeError: Cannot set property crypto of #<Object> which has only a getter).

What are our options? I'm pretty sure that @manzt 's PR #976 would fix this since it includes a fallback for crypto.randomUUID. So perhaps we update the test Node versions after that PR? Or just only test with Node 20 which is probably fine since Gosling is mainly to be run in a browser?

@manzt
Copy link
Member

manzt commented Oct 6, 2023

Or just only test with Node 20 which is probably fine since Gosling is mainly to be run in a browser?

Ya, I'm in favor of just using 20. Especially since it better reflects the environment Gosling actually runs in. We just need to communicate the change/requirement to the gosling team. We could also look into adding an .nvmrc, so users of nvm and fnm automatically get the right version of node when the cd into the gosling.js.

@etowahadams
Copy link
Contributor Author

That makes sense to me. I'll add a note about testing using Node 20 to the contributing doc and will add a .nvmrc. We can make an announcement to the Gosling channel when this PR is finalized.
cc: @sehilyi

@etowahadams
Copy link
Contributor Author

Removed mention of nvm based on comments today

gosling.embed(document.getElementById('gosling-container'), ${spec})
<div id="gosling-container"></div>
<script type="module">
import { embed } from 'https://esm.sh/gosling.js@${goslingVersion}?bundle';
Copy link
Member

@manzt manzt Oct 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only question I have here is whether the version of higlass and gosling.js will stay in sync over time. Unfortunately the names used in the styles are specific to the higlass version, so I don't know if there could be a case where higlass makes a patch (e.g., v1.11.8) but we have styles from 1.11.7 in our template and the two end up out of sync. I wonder if it's possible to do something like:

import { embed } from 'https://esm.sh/gosling.js@${goslingVersion}?bundle&deps=higlass@${higlassVersion}';

but I'm not sure if the deps is handled when bundle is used.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to use different react and react-dom versions as well that user wishes to use?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question. Ideally you could bundle and override dependency versions, but I'm not sure for ESM.sh if that is current possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just tested. Unfortunately, it seems to ignore the version of the dependencies. I tried using a lower version of HiGlass and I still got HiGlass v1.12.4: http://higlass.io/ in the console. What I'll try next is to use the pre-bundled peer dependencies in an import map.

import { embed } from 'https://esm.sh/[email protected]?bundle&deps=higlass@$1.11.7';

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't have any luck using unbundled gosling.js with bundled peer dependencies either using an importmap.

The problem seems to be that HiGlass has "pixi.js": "^5.0.3" as a peer dependency. One of the pixi subpackages called @pixi/polyfill relies on a package called es6-promise-polyfill which doesn't have the export that @pixi/polyfill expects. Thus I get a The requested module '/v133/[email protected]/es2022/es6-promise-polyfill.mjs' does not provide an export named 'Polyfill' error when trying to import HiGlass.

Looking at that version of es6-promise-pollyfill it does look like there is export called Polyfill but I don't think it gets converted in a way that is accessible in the ESM version that esm.sh generates.

How hard it would it be to upgrade the pixi version that HiGlass uses to v6?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a PR to HiGlass to upgrade Pixi #977

Copy link
Member

@manzt manzt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome. Thanks for all your work on this Etowah, looking great. Just one thought about esm.sh, otherwise LGTM!

embed/index.ts Show resolved Hide resolved
knip.config.json Show resolved Hide resolved
"module": "dist/gosling.es.js",
"types": "dist/src/index.d.ts",
"files": [
"dist"
],
"type": "module",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup! Making things work nice (like Vite) might require upgrading those deps.

scripts/setup-vitest.js Show resolved Hide resolved
src/data-fetchers/gff/gff-worker.ts Show resolved Hide resolved
vite.config.mjs Outdated Show resolved Hide resolved
@manzt
Copy link
Member

manzt commented Oct 14, 2023

Ah, one thing I forgot. We have branch protection rules that require "Test (14.x)" and "Test (16.x)" to pass to merge into master. That's why "Some checks haven't completed yet". You removed these workflows in this PR, so that's why it's still waiting for them to complete. We should be ok to remove these rules in Settings (since they will never fulfill) and maybe add one for the node test workflow.

package.json Show resolved Hide resolved
package.json Show resolved Hide resolved
Comment on lines -29 to -30
// export * as d3Queue from 'd3-queue';
// export * as d3Request from 'd3-request';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intended? Could be removed if not needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exports ford3Queue and d3Request were commented out so I just removed them. Perhaps they're unused in the parts of HiGlass that Gosling uses?

@sehilyi
Copy link
Member

sehilyi commented Oct 16, 2023

@manzt @etowahadams Removed the "Test (14.x)" and "Test (16.x)" branch protection rules. I will add one for 20.x after this is merged.

@sehilyi sehilyi mentioned this pull request Oct 20, 2023
7 tasks
@manzt
Copy link
Member

manzt commented Oct 24, 2023

Released HiGlass v1.13

@etowahadams
Copy link
Contributor Author

Amazing thanks @manzt! Will try it out tomorrow.

@etowahadams
Copy link
Contributor Author

The polyfill error is resolved! Now encountering a new error due to HiGlass not being ESM.

// [OLD] This still uses [email protected] and we get the polyfill import error
import { embed } from 'https://esm.sh/[email protected]';

// [NEW] This uses [email protected]
// No more polyfill error (yay!). However, we get a new error
// higlass.mjs does not provide an export named 'HiGlassComponent
import { embed } from 'https://esm.sh/[email protected][email protected]'

Why is this failing? higlass.js is a UMD module. Esm.sh converts this into a ES module which has a single export:

// https://esm.sh/v133/[email protected]/es2022/higlass.mjs 
export {oNe as default};

So in gosling.mjs, this fails:

import { HiGlassComponent as ps } from "/v133/[email protected]/es2022/higlass.mjs";
// ERROR: higlass.mjs does not provide an export named 'HiGlassComponent 

Potential solutions

Add feature to esm.sh

One solution which would require adding a feature to esm.sh. Currently esm.sh allows you to specify named exports from CJS file:

import { HiGlassComponent } from "https://esm.sh/[email protected]?cjs-exports=HiGlassComponent";

This gets turned into the following in higlass.mjs, allowing HiGlassComponent to be imported.

export * from "/v133/[email protected]/X-dHMvSGlHbGFzc0NvbXBvbmVudA/es2022/higlass.mjs";
import __cjs_exports$ from "/v133/[email protected]/X-dHMvSGlHbGFzc0NvbXBvbmVudA/es2022/higlass.mjs";
export const { HiGlassComponent } = __cjs_exports$;

However, you can’t combine this feature with the ?deps option

// This doesn't work :(
import { embed } from 'https://esm.sh/[email protected][email protected]?cjs-exports=HiGlassComponent'

So we would have to submit a PR to esm.sh to add this feature.

ESM build for Higlass

Once again we return to this. I’m ready to make this a priority if others are onboard with me doing so.

Add back the UMD build

We could also just bring back the UMD build as a short term fix to merge this PR. This is tempting.

Thoughts? @manzt @sehilyi

@etowahadams
Copy link
Contributor Author

Just waiting on higlass/higlass#1171 and we should be good to go!

@etowahadams
Copy link
Contributor Author

This should be everything. Thanks for all the work on HiGlass Trevor!

@etowahadams etowahadams merged commit 5457f16 into master Oct 26, 2023
5 checks passed
@etowahadams etowahadams deleted the etowahadams/clean-build branch October 26, 2023 21:10
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

Successfully merging this pull request may close these issues.

3 participants