ebi-webcomponents / protvista-uniprot

The ProtVista tool for the UniProt website
MIT License
12 stars 6 forks source link

error loading component in an angular project #42

Closed KeithKelleher closed 2 years ago

KeithKelleher commented 2 years ago

I'm trying to load the protvista-uniprot component in an angular project. It's running into an error when I import protvista-uniprot.js, which seems like a webpack loading error, but the loader seems configured in webpack.config.js.

Any ideas?

./node_modules/protvista-uniprot/dist/es/icons/download.svg:2:0 - Error: Module parse failed: Unexpected token (2:0) You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders

./node_modules/protvista-uniprot/dist/es/icons/spinner.svg:1:0 - Error: Module parse failed: Unexpected token (1:0) You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders

Minimal repro repo here: https://github.com/KeithKelleher/protvista-angular

xwatkins commented 2 years ago

Hi Keith, The issue is that by importing protvista-uniprot as a module, you're also (currently) responsible for transforming what it is loading (like SVGs in this case). This will change in the future as we will deprecate the commonJS version of the module now that imports are possible directly in the browser. If you don't want to handle the transformation of the SVGs as part of your build process, you could just load the commonJS version directly in your protvista-component.html file for now:

<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/protvista-uniprot@latest/dist/protvista-uniprot.js" ></script>
...
<protvista-uniprot accession="P05067"></protvista-uniprot>
<protvista-uniprot

Let me know if any further questions, Xavier

KeithKelleher commented 2 years ago

Thanks Xavier,

That helps. I can add the commonJS version to angular's index.html to get it to show up. It's not ideal to add it to index.html, but Angular won't allow scripts anywhere else. Dynamically loading the script, like we do for some others, doesn't work because we run into the same error with the svg loader. Going down the other road, I was able to customize angular's build process to use the svg loader and get it to build without error. I could show the component as long as the accession was hardcoded into the html tag. Trying to update it dynamically based on what target we were looking at didn't change the data that was showing. Maybe the component doesn't respond to changes in the uniprot accession? or allow setting it after the component is created?

xwatkins commented 2 years ago

Glad you got it to work! It should update if the accession is changed, will have a look at the component lifecycle and report back...

KeithKelleher commented 2 years ago

Here's an outline of what I did to get it to work with Angular, if anyone else needs to do the same. It worked to have the commonjs module loading from index.html, but we'd prefer not to have that load for every page, since it is fairly big, so the steps below show how to load it dynamically in an angular component.

My custom custom-webpack.config.js looks like this:

const webpack = require('webpack');

module.exports = { module: { rules: [ { test: /.svg$/i, loader: 'svg-inline-loader', } ] } };

When my angular component loads (in ngOnInit) I load the module (our fork is called ncats-protvista-uniprot).

import('ncats-protvista-uniprot').then(res => { window.customElements.get('protvista-uniprot') || window.customElements.define('protvista-uniprot', res.default); const viewer = this.renderer.createElement('protvista-uniprot'); viewer.setAttribute('accession', this.target.accession); this.viewerContainer.nativeElement.insertAdjacentElement('beforeend', viewer);

This loads the module, and registers the custom element, if it's not already registered. Then it's created, accession is set, and inserted into the DOM. I was having trouble getting the whole component to update when the accession changes, so if that ever happens, we're removing the old one, and inserting a new one.